From fd46c9afbd5f529d14922b5023b8e8106a68cf25 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 23 Jul 2019 22:19:32 -0500 Subject: [PATCH 01/74] A very rough initial implementation --- src/sage/combinat/all.py | 6 +- src/sage/combinat/plane_partition.py | 573 ++++++++++++++++++++++++++- 2 files changed, 556 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 076fa047d4b..476a9b36bab 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -123,8 +123,10 @@ 'TruncatedStaircases')) # Plane Partitions -lazy_import('sage.combinat.plane_partition', ('PlanePartition', - 'PlanePartitions')) +#lazy_import('sage.combinat.plane_partition', ('PlanePartition', +# 'PlanePartitions')) + +from .plane_partition import PlanePartition, PlanePartitions # Parking Functions lazy_import('sage.combinat.non_decreasing_parking_function', diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index ff0f9df40d3..ee8573d1ca7 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -37,7 +37,7 @@ from sage.combinat.tableau import Tableau -@add_metaclass(InheritComparisonClasscallMetaclass) +#@add_metaclass(InheritComparisonClasscallMetaclass) class PlanePartition(ClonableArray): r""" A plane partition. @@ -69,7 +69,7 @@ class PlanePartition(ClonableArray): sage: TestSuite(PP).run() """ @staticmethod - def __classcall_private__(cls, PP, box_size=None): + def __classcall_private__(cls, PP): """ Construct a plane partition with the appropriate parent. @@ -79,12 +79,14 @@ def __classcall_private__(cls, PP, box_size=None): sage: PP.parent() is PlanePartitions((3,4,4)) True """ + if isinstance(PP,PlanePartition): + return PP if box_size is None: if PP: box_size = (len(PP), len(PP[0]), PP[0][0]) else: box_size = (0, 0, 0) - return PlanePartitions(box_size)(PP) + return PlanePartitions(box_size, symmetry=symmetry)(PP) def __init__(self, parent, PP, check=True): """ @@ -705,7 +707,66 @@ def is_TSSCPP(self): """ return self.is_TSPP() and self.is_SCPP() + class PlanePartitions(UniqueRepresentation, Parent): + r""" + A factory class for plane partitions. + + PlanePartitions([a,b,c]) returns the class of plane partitions that fit + inside an a \times b \times c box. + + Optional keyword is 'symmetry'. + + Describe options. + + """ + @staticmethod + def __classcall_private__(cls, box_size, symmetry=None): + """ + Return correct parent based on input. + + EXAMPLES:: + + sage: 1+1 + 2 + """ + if len(box_size) != 3: + raise ValueError("invalid box size") + if symmetry == None: + return PlanePartitions_all(box_size) + elif symmetry == 'TSPP': + return PlanePartitions_TSPP(box_size) + elif symmetry == 'SPP': + return PlanePartitions_SPP(box_size) + elif symmetry == 'CSPP': + return PlanePartitions_CSPP(box_size) + elif symmetry == 'TSSCPP': + return PlanePartitions_TSSCPP(box_size) + else: + raise ValueError("invalid symmetry class option; must be None, 'TSPP', 'SPP', 'CSPP', or 'TSCCPP' ") + + + + + Element = PlanePartition + + + def __init__(self, box_size, symmetry=None): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: S = PlanePartitions() + sage: TestSuite(S).run() # long time + """ + self.symmetry=symmetry + self._box = box_size + # Tableaux.__init__(self, **kwds) + # ClonableArray.__init__(self) + + +class PlanePartitions_all(PlanePartitions): r""" All plane partitions inside a rectangular box of given side lengths. @@ -729,6 +790,8 @@ class PlanePartitions(UniqueRepresentation, Parent): :class:`PlanePartition` """ + + @staticmethod def __classcall_private__(cls, box_size): """ @@ -741,7 +804,7 @@ def __classcall_private__(cls, box_size): sage: P1 is P2 True """ - return super(PlanePartitions, cls).__classcall__(cls, tuple(box_size)) + return super(PlanePartitions_all, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): r""" @@ -752,12 +815,10 @@ def __init__(self, box_size): sage: PP = PlanePartitions((4,3,2)) sage: TestSuite(PP).run() """ - if len(box_size) != 3: - raise ValueError("invalid box size") + super(PlanePartitions_all,self ).__init__(box_size) self._box = box_size - Parent.__init__(self, category=FiniteEnumeratedSets()) - def _repr_(self): + def __repr__(self): """ Return a string representation of ``self``. @@ -766,8 +827,8 @@ def _repr_(self): sage: PlanePartitions((4,3,2)) Plane partitions inside a 4 x 3 x 2 box """ - return "Plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Plane partitions inside a %s x %s x %s box" % (self._box[0], self._box[1], self._box[2]) +# return "Plane partitions inside a box" def __iter__(self): """ @@ -780,16 +841,68 @@ def __iter__(self): Plane partition [[1, 0]], Plane partition [[1, 1]]] """ - A = self._box[0] - B = self._box[1] - C = self._box[2] - from sage.combinat.tableau import SemistandardTableaux - for T in SemistandardTableaux([B for i in range(A)], max_entry=C+A): - PP = [[0 for i in range(B)] for j in range(A)] - for r in range(A): - for c in range(B): - PP[A-1-r][B-1-c] = T[r][c] - r - 1 - yield self.element_class(self, PP, check=False) +# A = self._box[0] +# B = self._box[1] +# C = self._box[2] +# from sage.combinat.tableau import SemistandardTableaux +# for T in SemistandardTableaux([B for i in range(A)], max_entry=C+A): +# PP = [[0 for i in range(B)] for j in range(A)] +# for r in range(A): +# for c in range(B): +# PP[A-1-r][B-1-c] = T[r][c] - r - 1 +# yield self.element_class(self, PP, check=False) + def componentwise_comparer(thing1,thing2): + if len(thing1) == len(thing2): + if all(thing1[i] <= thing2[i] for i in range(len(thing1))): + return True + return False + def product_of_chains_poset(list_of_chain_lengths): + elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) + return Poset((elem, componentwise_comparer)) + + a = self._box[0] + b = self._box[1] + c = self._box[2] + + pocp = product_of_chains_poset([a,b,c]) + + matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + + #iterate through each antichain of product of chains poset with paramaters (a,b,c) + for acl in pocp.antichains_iterator(): + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + + #ac format ex: [x,y,z] + #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + + matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions + + matrixList.sort() + current = 0 + while current < len(matrixList): + yield self.element_class(self, matrixList[current]) + current += 1 + def cardinality(self): r""" @@ -856,4 +969,422 @@ def leq(thing1, thing2): Z[C[0]][C[1]] += 1 return self.element_class(self, Z, check=False) - Element = PlanePartition +class PlanePartitions_TSPP(PlanePartitions): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_TSPP, self).__init__(box_size=box_size) + self._box=box_size + + def _repr_(self): + return " Totally Symmetric Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + + def __iter__(self): + """ + EXAMPLES: + + + + """ + def componentwise_comparer(thing1,thing2): + if len(thing1) == len(thing2): + if all(thing1[i] <= thing2[i] for i in range(len(thing1))): + return True + return False + a=self._box[0] + b=self._box[1] + c=self._box[2] + pl = [] + for x in range(0,a): + for y in range(x, b): + for z in range(y,c): + pl.append((x,y,z)) + + pocp = Poset((pl,componentwise_comparer)) + matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + #iterate through each antichain of product of chains poset with paramaters (a,b,c) + for acl in pocp.antichains_iterator(): + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + + #ac format ex: [x,y,z] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) #x,y,z + ppMatrix[z][x] = (y+1) #y,z,x + ppMatrix[x][y] = (z+1) #z,x,y + ppMatrix[z][y] = (x+1) #x,z,y + ppMatrix[x][z] = (y+1) #y,x,z + ppMatrix[y][x] = (z+1) #z,y,x + + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + + matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions + + matrixList.sort() + + + current = 0 + while current < len(matrixList): + yield self.element_class(self, matrixList[current]) + current += 1 + + + +class PlanePartitions_SPP(PlanePartitions): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_SPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + if box_size[1] != box_size[2]: + raise ValueError("invalid box size") + super(PlanePartitions_SPP, self).__init__(box_size=box_size) + self._box=box_size + + def _repr_(self): + return " Symmetric Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + + def __iter__(self): + def componentwise_comparer(thing1,thing2): + if len(thing1) == len(thing2): + if all(thing1[i] <= thing2[i] for i in range(len(thing1))): + return True + return False + a=self._box[0] + b=self._box[1] + c=self._box[2] + pl = [] + for x in range(0,a): + for y in range(0, b): + for z in range(0,c): + if z <= y: + pl.append((x,y,z)) + + + pocp = Poset((pl,componentwise_comparer)) + + matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + #iterate through each antichain of product of chains poset with paramaters (a,b,c) + for acl in pocp.antichains_iterator(): + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + #ac format ex: [x,y,z] + #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0) and i>=j: + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + elif j>i: + ppMatrix[i][j] = ppMatrix[j][i] + + matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions + matrixList.sort() + current = 0 + while current < len(matrixList): + yield self.element_class(self, matrixList[current]) + current += 1 + + +class PlanePartitions_CSPP(PlanePartitions): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + if (box_size[0] != box_size[1] or box_size[1] != box_size[2]): + raise ValueError("invalid box size; must be (r,r,r)") + super(PlanePartitions_CSPP, self).__init__(box_size=box_size) + self._box=box_size + + def _repr_(self): + return " Cyclically Symmetric Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + + def __iter__(self): + def componentwise_comparer2(thing1,thing2): + x = thing2[0] + y = thing2[1] + z = thing2[2] + + if componentwise_comparer(thing1,(x,y,z)) or componentwise_comparer(thing1,(z,x,y)) or componentwise_comparer(thing1,(y,z,x)): + return True + return False + + pl = [] + for x in range(0,a): + for y in range(0, b): + for z in range(x,c): + if y <= z and (x != z or y == x): + pl.append((x,y,z)) + + pocp = Poset((pl,componentwise_comparer2)) + matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + #iterate through each antichain of product of chains poset with paramaters (a,b,c) + for acl in pocp.antichains_iterator(): + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + + #ac format ex: [x,y,z] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) + ppMatrix[z][x] = (y+1) + ppMatrix[x][y] = (z+1) + + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + + matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions + + matrixList.sort() + + current = 0 + while current < len(matrixList): + yield self.element_class(self, matrixList[current]) + current += 1 + +class PlanePartitions_TSSCPP(PlanePartitions): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_TSSCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): + raise ValueError("invalid box size; must be (2r,2r,2r)") + super(PlanePartitions_TSSCPP, self).__init__(box_size=box_size) + self._box=box_size + + def _repr_(self): + return " Totally Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self): + def componentwise_comparer(thing1,thing2): + if len(thing1) == len(thing2): + if all(thing1[i] <= thing2[i] for i in range(len(thing1))): + return True + return False + a=self._box[0] + b=self._box[1] + c=self._box[2] + n = a + b = n + c = n + + pl = [] + for x in range(0,n/2 - 2 + 1): + for y in range(x, n/2 - 2 + 1): + for z in range(0,n/2 - 2 + 1): + if z <= n/2 - 2 - y: + pl.append((x,y,z)) + + pocp = Poset((pl,componentwise_comparer)) + + matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + #iterate through each antichain of product of chains poset with paramaters (a,b,c) + for acl in pocp.antichains_iterator(): + #ac format ex: [x,y,z] + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + width = n/2 - 1 + height = n/2 - 1 + + #generate inner triagle + for i in range(width): + for j in range(height): + if(i <= j): + for ac in acl: + if ac[0] == i and ac[1] == j: + zVal = ac[2] + matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] + if zVal + 1 > matrixVal: + ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 + + #fill back + for i in range(width): + i = width-(i+1) + i = i + n/2 + for j in range(height): + j = height-(j+1) + j = j + n/2 + if (ppMatrix[i][j] == 0): + if i >= j: + iValue = 0 + jValue = 0 + if i < n: + iValue = ppMatrix[i+1][j] + if j < n: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + + + #fill half of triangle symmetrically + for i in range(width): + i = i + n/2 + for j in range(height): + j = j + n/2 + if i >= j: + ppMatrix[j][i] = ppMatrix[i][j] + + #upper left box + for i in range(n/2): + for j in range(n/2): + ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] + + + #fill in lower left cube with values n/2 + for i in range(n/2): + for j in range(n/2): + x = i + y = j + if(ppMatrix[x][y+(n/2)]) == 0: + ppMatrix[x][y+(n/2)] = n/2 + if(ppMatrix[x+(n/2)][y]) == 0: + ppMatrix[x+(n/2)][y] = n/2 + + + #add and subtract values from lower left cube to be rotation of lower right cube + for i in range(n/2): + for j in range(n/2): + x = i+(n/2) + y = j+(n/2) + if ppMatrix[x][y] > 0: + z = ppMatrix[x][y] + for cVal in range(z): + #build onto lower left cube + ppMatrix[x][0+cVal] += 1 + #carve out of lower left cube + ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 + + #fill in upper right cube symmetrically with lower left + for i in range(n/2): + for j in range(n/2): + ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] + + matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions + + matrixList.sort() + + current = 0 + while current < len(matrixList): + yield self.element_class(self, matrixList[current]) + current += 1 From 38e8b71dc6a32a4135245dcf4730e1b53e158d3e Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 25 Jul 2019 13:11:02 -0500 Subject: [PATCH 02/74] Potential class structure fix --- src/sage/combinat/all.py | 6 +- src/sage/combinat/plane_partition.py | 350 +++++++++++++-------------- 2 files changed, 168 insertions(+), 188 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 476a9b36bab..6d0fff38ad1 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -123,10 +123,10 @@ 'TruncatedStaircases')) # Plane Partitions -#lazy_import('sage.combinat.plane_partition', ('PlanePartition', -# 'PlanePartitions')) +lazy_import('sage.combinat.plane_partition', ('PlanePartition', + 'PlanePartitions')) -from .plane_partition import PlanePartition, PlanePartitions +#from .plane_partition import PlanePartition, PlanePartitions # Parking Functions lazy_import('sage.combinat.non_decreasing_parking_function', diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index ee8573d1ca7..907a9af2e30 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -26,48 +26,20 @@ from six.moves import range from six import add_metaclass -from sage.structure.list_clone import ClonableArray +from sage.structure.list_clone import ClonableList from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset from sage.rings.integer import Integer from sage.misc.all import prod from sage.combinat.tableau import Tableau -#@add_metaclass(InheritComparisonClasscallMetaclass) -class PlanePartition(ClonableArray): - r""" - A plane partition. - - A *plane partition* is a stack of cubes in the positive orthant. - - INPUT: - - - ``PP`` -- a list of lists which represents a tableau - - - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, - where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, - `y`-axis, `z`-axis, respectively; if this is not given, it is - determined by the smallest box bounding ``PP`` - - OUTPUT: - - The plane partition whose tableau representation is ``PP``. - - EXAMPLES:: - - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP - Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] - - TESTS:: - - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: TestSuite(PP).run() - """ +@add_metaclass(InheritComparisonClasscallMetaclass) +class PlanePartition(ClonableList): @staticmethod def __classcall_private__(cls, PP): """ @@ -79,28 +51,17 @@ def __classcall_private__(cls, PP): sage: PP.parent() is PlanePartitions((3,4,4)) True """ - if isinstance(PP,PlanePartition): + if isinstance(PP,PlanePartition): return PP - if box_size is None: - if PP: - box_size = (len(PP), len(PP[0]), PP[0][0]) - else: - box_size = (0, 0, 0) - return PlanePartitions(box_size, symmetry=symmetry)(PP) - - def __init__(self, parent, PP, check=True): - """ - Initialize ``self``. + pp = PlanePartitions() + return pp.element_class(pp, PP) # The check() will raise the appropriate error +# return PlanePartitions()(PP) - EXAMPLES:: - - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: TestSuite(PP).run() - """ - ClonableArray.__init__(self, parent, PP, check=check) - self._max_x = parent._box[0] - self._max_y = parent._box[1] - self._max_z = parent._box[2] + def __init__(self, parent, pp, check=True): + if isinstance(pp, PlanePartition): + ClonableList.__init__(self, parent, pp, check=False) + pp = [tuple(_) for _ in pp] + ClonableList.__init__(self, parent, pp, check=check) def check(self): """ @@ -111,14 +72,14 @@ def check(self): sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.check() """ - if len(self) == 0: - return - if len(self) > self.parent()._box[0]: - raise ValueError("too big in z direction") - if len(self[0]) > self.parent()._box[1]: - raise ValueError("too big in y direction") - if self[0][0] > self.parent()._box[2]: - raise ValueError("too big in x direction") + for row in self: + if not all(c >= 0 for c in row): + raise ValueError("Entries not all nonnegative") + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + raise ValueError("Not weakly decreasing along rows") + for row, next in zip(self, self[1:]): + if not all(row[c] >= next[c] for c in range(len(next))): + raise ValueError("Not weakly decreasing along columns") def _repr_(self): """ @@ -705,7 +666,8 @@ def is_TSSCPP(self): sage: PP.is_TSSCPP() True """ - return self.is_TSPP() and self.is_SCPP() + return self.is_TSPP() and self.is_SCPP() + class PlanePartitions(UniqueRepresentation, Parent): @@ -721,7 +683,7 @@ class PlanePartitions(UniqueRepresentation, Parent): """ @staticmethod - def __classcall_private__(cls, box_size, symmetry=None): + def __classcall_private__(cls, *args, **kwds): """ Return correct parent based on input. @@ -730,20 +692,29 @@ def __classcall_private__(cls, box_size, symmetry=None): sage: 1+1 2 """ - if len(box_size) != 3: - raise ValueError("invalid box size") - if symmetry == None: - return PlanePartitions_all(box_size) - elif symmetry == 'TSPP': - return PlanePartitions_TSPP(box_size) - elif symmetry == 'SPP': - return PlanePartitions_SPP(box_size) - elif symmetry == 'CSPP': - return PlanePartitions_CSPP(box_size) - elif symmetry == 'TSSCPP': - return PlanePartitions_TSSCPP(box_size) + symmetry = kwds.get('symmetry', None) + if not args: + return PlanePartitions_all() else: - raise ValueError("invalid symmetry class option; must be None, 'TSPP', 'SPP', 'CSPP', or 'TSCCPP' ") + box_size = None + if args: + # The first arg could be either a size or a box size + if isinstance(args[0], (int, Integer)): + return PlanePartitions_n(args[0]) + else: + box_size = args[0] + if symmetry == None: + return PlanePartitions_box(box_size) + elif symmetry == 'TSPP': + return PlanePartitions_TSPP(box_size) + elif symmetry == 'SPP': + return PlanePartitions_SPP(box_size) + elif symmetry == 'CSPP': + return PlanePartitions_CSPP(box_size) + elif symmetry == 'TSSCPP': + return PlanePartitions_TSSCPP(box_size) + else: + raise ValueError("invalid symmetry class option; must be None, 'TSPP', 'SPP', 'CSPP', or 'TSCCPP' ") @@ -751,47 +722,69 @@ def __classcall_private__(cls, box_size, symmetry=None): Element = PlanePartition - def __init__(self, box_size, symmetry=None): - """ - Initialize ``self``. + + +class PlanePartitions_all(PlanePartitions): + r""" + All plane partitions of any size + + + + :class:`PlanePartition` + """ + + + def __init__(self): + r""" + Initialize ``self`` EXAMPLES:: - sage: S = PlanePartitions() - sage: TestSuite(S).run() # long time + sage: PP = PlanePartitions((4,3,2)) + sage: TestSuite(PP).run() """ - self.symmetry=symmetry - self._box = box_size - # Tableaux.__init__(self, **kwds) - # ClonableArray.__init__(self) + super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) + def __repr__(self): + """ + Return a string representation of ``self``. -class PlanePartitions_all(PlanePartitions): - r""" - All plane partitions inside a rectangular box of given side lengths. + EXAMPLES:: - INPUT: + sage: PlanePartitions((4,3,2)) + Plane partitions inside a 4 x 3 x 2 box + """ + return "Plane partitions " +# return "Plane partitions inside a box" - - ``box_size`` -- a triple of positive integers indicating the size - of the box containing the plane partition + def __contains(self, pp): + """ + Check to see that ``self`` is a valid plane partition. - EXAMPLES: + EXAMPLES:: - This will create an instance to manipulate the plane partitions - in a `4 \times 3 \times 2` box:: + sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: PP.check() + """ + for row in pp: + if not all(c >= 0 for c in row): + return False + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + return False + for row, next in zip(pp, pp[1:]): + if not all(row[c] >= next[c] for c in range(len(next))): + return False + return True + + +class PlanePartitions_box(PlanePartitions_all): + r""" + All plane partitions of any size - sage: P = PlanePartitions((4,3,2)) - sage: P - Plane partitions inside a 4 x 3 x 2 box - sage: P.cardinality() - 490 - .. SEEALSO:: :class:`PlanePartition` """ - - @staticmethod def __classcall_private__(cls, box_size): """ @@ -804,7 +797,7 @@ def __classcall_private__(cls, box_size): sage: P1 is P2 True """ - return super(PlanePartitions_all, cls).__classcall__(cls, tuple(box_size)) + return super(PlanePartitions_box, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): r""" @@ -815,7 +808,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions((4,3,2)) sage: TestSuite(PP).run() """ - super(PlanePartitions_all,self ).__init__(box_size) + super(PlanePartitions_box,self).__init__() self._box = box_size def __repr__(self): @@ -830,6 +823,8 @@ def __repr__(self): return "Plane partitions inside a %s x %s x %s box" % (self._box[0], self._box[1], self._box[2]) # return "Plane partitions inside a box" + + def __iter__(self): """ Iterate over ``self``. @@ -969,7 +964,29 @@ def leq(thing1, thing2): Z[C[0]][C[1]] += 1 return self.element_class(self, Z, check=False) -class PlanePartitions_TSPP(PlanePartitions): + + +class PlanePartitions_n(PlanePartitions_all): + + + def __init__(self, n): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_n, self).__init__() + self._n = n + + def _repr_(self): + return " Totally Symmetric Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + + + +class PlanePartitions_TSPP(PlanePartitions_all): @staticmethod def __classcall_private__(cls, box_size): @@ -992,82 +1009,14 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_TSPP, self).__init__(box_size=box_size) + super(PlanePartitions_TSPP, self).__init__() self._box=box_size def _repr_(self): return " Totally Symmetric Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - - def __iter__(self): - """ - EXAMPLES: - - - - """ - def componentwise_comparer(thing1,thing2): - if len(thing1) == len(thing2): - if all(thing1[i] <= thing2[i] for i in range(len(thing1))): - return True - return False - a=self._box[0] - b=self._box[1] - c=self._box[2] - pl = [] - for x in range(0,a): - for y in range(x, b): - for z in range(y,c): - pl.append((x,y,z)) - - pocp = Poset((pl,componentwise_comparer)) - matrixList = [] #list of all PlaneParitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with paramaters (a,b,c) - for acl in pocp.antichains_iterator(): - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - - #ac format ex: [x,y,z] - for ac in acl: - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix[y][z] = (x+1) #x,y,z - ppMatrix[z][x] = (y+1) #y,z,x - ppMatrix[x][y] = (z+1) #z,x,y - ppMatrix[z][y] = (x+1) #x,z,y - ppMatrix[x][z] = (y+1) #y,x,z - ppMatrix[y][x] = (z+1) #z,y,x - - - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format - if acl != []: - for i in range(b): - i = b-(i+1) - for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): - iValue = 0 - jValue = 0 - if i < b-1: - iValue = ppMatrix[i+1][j] - if j < c-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - - matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions - - matrixList.sort() - - - current = 0 - while current < len(matrixList): - yield self.element_class(self, matrixList[current]) - current += 1 - - - -class PlanePartitions_SPP(PlanePartitions): +class PlanePartitions_SPP(PlanePartitions_all): @staticmethod def __classcall_private__(cls, box_size): @@ -1090,16 +1039,13 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - if box_size[1] != box_size[2]: - raise ValueError("invalid box size") - super(PlanePartitions_SPP, self).__init__(box_size=box_size) + super(PlanePartitions_SPP, self).__init__() self._box=box_size def _repr_(self): return " Symmetric Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): def componentwise_comparer(thing1,thing2): if len(thing1) == len(thing2): @@ -1156,7 +1102,8 @@ def componentwise_comparer(thing1,thing2): current += 1 -class PlanePartitions_CSPP(PlanePartitions): + +class PlanePartitions_CSPP(PlanePartitions_all): @staticmethod def __classcall_private__(cls, box_size): @@ -1179,16 +1126,13 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - if (box_size[0] != box_size[1] or box_size[1] != box_size[2]): - raise ValueError("invalid box size; must be (r,r,r)") - super(PlanePartitions_CSPP, self).__init__(box_size=box_size) + super(PlanePartitions_CSPP, self).__init__() self._box=box_size def _repr_(self): return " Cyclically Symmetric Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): def componentwise_comparer2(thing1,thing2): x = thing2[0] @@ -1246,7 +1190,42 @@ def componentwise_comparer2(thing1,thing2): yield self.element_class(self, matrixList[current]) current += 1 -class PlanePartitions_TSSCPP(PlanePartitions): + +class PlanePartitions_SCPP(PlanePartitions_all): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_SCPP, self).__init__() + self._box=box_size + + def _repr_(self): + return " Self Complementary Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + + + + +class PlanePartitions_TSSCPP(PlanePartitions_all): @staticmethod def __classcall_private__(cls, box_size): @@ -1271,13 +1250,14 @@ def __init__(self, box_size): """ if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): raise ValueError("invalid box size; must be (2r,2r,2r)") - super(PlanePartitions_TSSCPP, self).__init__(box_size=box_size) + super(PlanePartitions_TSSCPP, self).__init__() self._box=box_size def _repr_(self): return " Totally Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __iter__(self): def componentwise_comparer(thing1,thing2): if len(thing1) == len(thing2): From 0e10ab4f1e9bcf40904c716513f40510d4d26e26 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 25 Jul 2019 13:22:50 -0500 Subject: [PATCH 03/74] added a few more base symmetry classes --- src/sage/combinat/plane_partition.py | 66 ++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 907a9af2e30..53b131851ab 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -713,6 +713,10 @@ def __classcall_private__(cls, *args, **kwds): return PlanePartitions_CSPP(box_size) elif symmetry == 'TSSCPP': return PlanePartitions_TSSCPP(box_size) + elif symmetry == 'CSTCPP': + return PlanePartitions_CSTCPP(box_size) + elif symmetry == 'CSSCPP': + return PlanePartitions_CSSCPP(box_size) else: raise ValueError("invalid symmetry class option; must be None, 'TSPP', 'SPP', 'CSPP', or 'TSCCPP' ") @@ -1368,3 +1372,65 @@ def componentwise_comparer(thing1,thing2): while current < len(matrixList): yield self.element_class(self, matrixList[current]) current += 1 + +class PlanePartitions_CSTCPP(PlanePartitions_all): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_CSTCPP, self).__init__() + self._box=box_size + + def _repr_(self): + return " Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + +class PlanePartitions_CSSCPP(PlanePartitions_all): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_CSSCPP, self).__init__() + self._box=box_size + + def _repr_(self): + return " Cyclically Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + From 241a6ca1348cfd200c66ceb3a55556bf89d6071b Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 25 Jul 2019 13:42:25 -0500 Subject: [PATCH 04/74] Symmetry subclasses need to be based on the factory class, not the all class --- src/sage/combinat/plane_partition.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 53b131851ab..bc563bb2fa8 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -728,6 +728,10 @@ def __classcall_private__(cls, *args, **kwds): + + + + class PlanePartitions_all(PlanePartitions): r""" All plane partitions of any size @@ -781,7 +785,7 @@ def __contains(self, pp): return True -class PlanePartitions_box(PlanePartitions_all): +class PlanePartitions_box(PlanePartitions): r""" All plane partitions of any size @@ -812,7 +816,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions((4,3,2)) sage: TestSuite(PP).run() """ - super(PlanePartitions_box,self).__init__() + super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) self._box = box_size def __repr__(self): @@ -970,7 +974,7 @@ def leq(thing1, thing2): -class PlanePartitions_n(PlanePartitions_all): +class PlanePartitions_n(PlanePartitions): def __init__(self, n): @@ -990,7 +994,7 @@ def _repr_(self): -class PlanePartitions_TSPP(PlanePartitions_all): +class PlanePartitions_TSPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): @@ -1020,7 +1024,7 @@ def _repr_(self): return " Totally Symmetric Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) -class PlanePartitions_SPP(PlanePartitions_all): +class PlanePartitions_SPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): @@ -1043,7 +1047,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_SPP, self).__init__() + super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size def _repr_(self): @@ -1107,7 +1111,7 @@ def componentwise_comparer(thing1,thing2): -class PlanePartitions_CSPP(PlanePartitions_all): +class PlanePartitions_CSPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): @@ -1195,7 +1199,7 @@ def componentwise_comparer2(thing1,thing2): current += 1 -class PlanePartitions_SCPP(PlanePartitions_all): +class PlanePartitions_SCPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): @@ -1373,7 +1377,7 @@ def componentwise_comparer(thing1,thing2): yield self.element_class(self, matrixList[current]) current += 1 -class PlanePartitions_CSTCPP(PlanePartitions_all): +class PlanePartitions_CSTCPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): @@ -1404,7 +1408,7 @@ def _repr_(self): self._box[0], self._box[1], self._box[2]) -class PlanePartitions_CSSCPP(PlanePartitions_all): +class PlanePartitions_CSSCPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): From f75ed2a512f06799d7b68b4c2067385faecbc87a Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 25 Jul 2019 13:45:55 -0500 Subject: [PATCH 05/74] Symmetry classes seem to know they are finite sets now --- 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 bc563bb2fa8..8f66d707c4f 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -984,7 +984,7 @@ def __init__(self, n): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_n, self).__init__() + super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) self._n = n def _repr_(self): @@ -1017,7 +1017,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_TSPP, self).__init__() + super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size def _repr_(self): @@ -1258,7 +1258,7 @@ def __init__(self, box_size): """ if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): raise ValueError("invalid box size; must be (2r,2r,2r)") - super(PlanePartitions_TSSCPP, self).__init__() + super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size def _repr_(self): @@ -1400,7 +1400,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_CSTCPP, self).__init__() + super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size def _repr_(self): @@ -1431,7 +1431,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_CSSCPP, self).__init__() + super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size def _repr_(self): From d3a2f917e3d36dceecf4978395f2be738e70ad4c Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 25 Jul 2019 14:35:50 -0500 Subject: [PATCH 06/74] Added attribute for a PlanePartition instance that makes bounding box size of box of parent (if defined), and largest bounding box otherwise --- src/sage/combinat/plane_partition.py | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 8f66d707c4f..a90bf23f1d8 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -33,11 +33,13 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset +from sage.combinat.posets.poset_examples import Posets from sage.rings.integer import Integer from sage.misc.all import prod from sage.combinat.tableau import Tableau + @add_metaclass(InheritComparisonClasscallMetaclass) class PlanePartition(ClonableList): @staticmethod @@ -62,6 +64,17 @@ def __init__(self, parent, pp, check=True): ClonableList.__init__(self, parent, pp, check=False) pp = [tuple(_) for _ in pp] ClonableList.__init__(self, parent, pp, check=check) + if self.parent()._box is None: + if pp: + self._max_x = len(pp) + self._max_y = len(pp[0]) + self._max_z = pp[0][0] + else: + self._max_x = 0 + self._max_y = 0 + self._max_z = 0 + else: + (self._max_x, self._max_y, self._max_z) = self.parent()._box def check(self): """ @@ -751,6 +764,7 @@ def __init__(self): sage: PP = PlanePartitions((4,3,2)) sage: TestSuite(PP).run() """ + self._box = None super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) def __repr__(self): @@ -859,15 +873,15 @@ def componentwise_comparer(thing1,thing2): if all(thing1[i] <= thing2[i] for i in range(len(thing1))): return True return False - def product_of_chains_poset(list_of_chain_lengths): - elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) - return Poset((elem, componentwise_comparer)) +# def product_of_chains_poset(list_of_chain_lengths): +# elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) +# return Poset((elem, componentwise_comparer)) a = self._box[0] b = self._box[1] c = self._box[2] - pocp = product_of_chains_poset([a,b,c]) + pocp = posets.ProductOfChains([a,b,c]) matrixList = [] #list of all PlaneParitions with parameters(a,b,c) @@ -1142,6 +1156,11 @@ def _repr_(self): self._box[0], self._box[1], self._box[2]) def __iter__(self): + def componentwise_comparer(thing1,thing2): + if len(thing1) == len(thing2): + if all(thing1[i] <= thing2[i] for i in range(len(thing1))): + return True + return False def componentwise_comparer2(thing1,thing2): x = thing2[0] y = thing2[1] @@ -1150,7 +1169,9 @@ def componentwise_comparer2(thing1,thing2): if componentwise_comparer(thing1,(x,y,z)) or componentwise_comparer(thing1,(z,x,y)) or componentwise_comparer(thing1,(y,z,x)): return True return False - + a=self._box[0] + b=self._box[1] + c=self._box[2] pl = [] for x in range(0,a): for y in range(0, b): From 1c6f7cd861da57a2c09b0ce4e7a0bc459b654e63 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 25 Jul 2019 14:48:43 -0500 Subject: [PATCH 07/74] Added import statement for cartesian product until iterator code refactored --- 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 a90bf23f1d8..dbd5d133682 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -33,7 +33,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset -from sage.combinat.posets.poset_examples import Posets +from sage.categories.cartesian_product import cartesian_product from sage.rings.integer import Integer from sage.misc.all import prod from sage.combinat.tableau import Tableau @@ -873,15 +873,15 @@ def componentwise_comparer(thing1,thing2): if all(thing1[i] <= thing2[i] for i in range(len(thing1))): return True return False -# def product_of_chains_poset(list_of_chain_lengths): -# elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) -# return Poset((elem, componentwise_comparer)) + def product_of_chains_poset(list_of_chain_lengths): + elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) + return Poset((elem, componentwise_comparer)) a = self._box[0] b = self._box[1] c = self._box[2] - pocp = posets.ProductOfChains([a,b,c]) + pocp = product_of_chains_poset([a,b,c]) matrixList = [] #list of all PlaneParitions with parameters(a,b,c) From 97bc8dd3b7470fc482b64dce2bfca232fd781fce Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 00:51:20 -0500 Subject: [PATCH 08/74] Iterator for plane partitions of fixed size implemented, beginning of documentation --- src/sage/combinat/plane_partition.py | 270 +++++++++++++++++++-------- 1 file changed, 196 insertions(+), 74 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index dbd5d133682..c050b1f6f48 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -33,6 +33,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset +from sage.combinat.posets.poset_examples import posets from sage.categories.cartesian_product import cartesian_product from sage.rings.integer import Integer from sage.misc.all import prod @@ -49,17 +50,34 @@ def __classcall_private__(cls, PP): EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1], [2,1,1], [1,1]]) - sage: PP.parent() is PlanePartitions((3,4,4)) - True + sage: p = PlanePartition([[2,1],[1]]) + sage: TestSuite(t).run() + + sage: p.parent() + Plane partitions + sage: p.category() + Category of elements of plane partitions + sage: type(p) + """ if isinstance(PP,PlanePartition): return PP pp = PlanePartitions() return pp.element_class(pp, PP) # The check() will raise the appropriate error -# return PlanePartitions()(PP) def __init__(self, parent, pp, check=True): + r""" + Initialize a plane partition. + + TESTS:: + + sage: a = PlanePartitions()([[2,1],[1]]) + sage: b = PlanePartitions([2,2,2])([[2,1],[1])) + sage: c = PlanePartitions(4)([[2,1],[1]]) + + Add more tests to show which parent a,b,c receive, check that a==b, and b==c, but a is not b, and b is not c. + + """ if isinstance(pp, PlanePartition): ClonableList.__init__(self, parent, pp, check=False) pp = [tuple(_) for _ in pp] @@ -82,8 +100,16 @@ def check(self): EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.check() + sage: a = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: a.check() + sage: b = PlanePartition([[1,2],[1]]) + Traceback (most recent call last): + ... + ValueError: Not weakly decreasing along rows + sage: c = PlanePartition([[1,1],[2]]) + Traceback (most recent call last): + ... + ValueError: Not weakly decreasing along columns """ for row in self: if not all(c >= 0 for c in row): @@ -485,6 +511,14 @@ def complement(self, tableau_only=False): r""" Return the complement of ``self``. + If the parent of ``self'' consists only of partitions inside a given + box, then the complement is taken in this box. Otherwise, the + complement is taken in the smallest box containing the plane partition. + + If ``tableau_only'' is set to ``True'', then only the tableau + consisting of the projection of boxes size onto the xy-plane + is returned instead of a PlanePartition object. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -510,6 +544,10 @@ def transpose(self, tableau_only=False): r""" Return the transpose of ``self``. + If ``tableau_only'' is set to ``True'', then only the tableau + consisting of the projection of boxes size onto the xy-plane + is returned instead of a PlanePartition object. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -697,13 +735,21 @@ class PlanePartitions(UniqueRepresentation, Parent): """ @staticmethod def __classcall_private__(cls, *args, **kwds): - """ - Return correct parent based on input. + r""" + This is a factory class which returns the appropriate parent based on + arguments. See the documentation for :class:`PlanePartitions` + for more information. - EXAMPLES:: + TESTS:: - sage: 1+1 - 2 + sage: PlanePartitions() + Plane partitions + sage: PlanePartitions([3,3,3]) + Plane partitions inside a 3 x 3 x 3 box + sage: PlanePartitions(3) + 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 """ symmetry = kwds.get('symmetry', None) if not args: @@ -734,8 +780,6 @@ def __classcall_private__(cls, *args, **kwds): raise ValueError("invalid symmetry class option; must be None, 'TSPP', 'SPP', 'CSPP', or 'TSCCPP' ") - - Element = PlanePartition @@ -747,22 +791,29 @@ def __classcall_private__(cls, *args, **kwds): class PlanePartitions_all(PlanePartitions): r""" - All plane partitions of any size - + All plane partitions. + .. TODO: - :class:`PlanePartition` + Consider giving this the structure of disjoint union of the classes + PlanePartitions(n) for n an integer. """ def __init__(self): r""" - Initialize ``self`` + Initializes the class of all increasing tableaux. - EXAMPLES:: + .. WARNING:: - sage: PP = PlanePartitions((4,3,2)) - sage: TestSuite(PP).run() + Input is not checked; please use :class:`IncreasingTableaux` to + ensure the options are properly parsed. + + TESTS:: + + sage: from sage.combinat.plane_partition import PlanePartition_all + sage: P = PlanePartition_all() + sage: TestSuite(P).run() # long time """ self._box = None super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) @@ -773,20 +824,20 @@ def __repr__(self): EXAMPLES:: - sage: PlanePartitions((4,3,2)) - Plane partitions inside a 4 x 3 x 2 box + sage: PlanePartitions() + Plane partitions """ - return "Plane partitions " -# return "Plane partitions inside a box" + return "Plane partitions" - def __contains(self, pp): + def __contains__(self, pp): """ Check to see that ``self`` is a valid plane partition. - EXAMPLES:: - - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.check() + .. TODO: + + Figure out how redundant this is, given that the check function + exists for the factor class. Maybe only need __contains__ + on the fixed size and symmetry classes? """ for row in pp: if not all(c >= 0 for c in row): @@ -801,11 +852,7 @@ def __contains(self, pp): class PlanePartitions_box(PlanePartitions): r""" - All plane partitions of any size - - - - :class:`PlanePartition` + All plane partitions that fit inside a box of a specified size. """ @staticmethod def __classcall_private__(cls, box_size): @@ -823,7 +870,8 @@ def __classcall_private__(cls, box_size): def __init__(self, box_size): r""" - Initialize ``self`` + Initializes the class of plane partitions that fit in a box of a + specified size. EXAMPLES:: @@ -868,20 +916,21 @@ def __iter__(self): # for c in range(B): # PP[A-1-r][B-1-c] = T[r][c] - r - 1 # yield self.element_class(self, PP, check=False) - def componentwise_comparer(thing1,thing2): - if len(thing1) == len(thing2): - if all(thing1[i] <= thing2[i] for i in range(len(thing1))): - return True - return False - def product_of_chains_poset(list_of_chain_lengths): - elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) - return Poset((elem, componentwise_comparer)) +# def componentwise_comparer(thing1,thing2): +# if len(thing1) == len(thing2): +# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): +# return True +# return False +# def product_of_chains_poset(list_of_chain_lengths): +# elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) +# return Poset((elem, componentwise_comparer)) a = self._box[0] b = self._box[1] c = self._box[2] - pocp = product_of_chains_poset([a,b,c]) +# pocp = product_of_chains_poset([a,b,c]) + pocp = posets.ProductOfChains([a,b,c]) matrixList = [] #list of all PlaneParitions with parameters(a,b,c) @@ -911,14 +960,15 @@ def product_of_chains_poset(list_of_chain_lengths): if j < c-1: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) + yield self.element_class(self, ppMatrix) - matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions +# matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions - matrixList.sort() - current = 0 - while current < len(matrixList): - yield self.element_class(self, matrixList[current]) - current += 1 +# matrixList.sort() +# current = 0 +# while current < len(matrixList): +# yield self.element_class(self, matrixList[current]) +# current += 1 def cardinality(self): @@ -948,8 +998,8 @@ def cardinality(self): def box(self): """ - Return the sizes of the box of the plane partitions of ``self`` - are contained in. + Return the size of the box of the plane partition of ``self`` + is contained in. EXAMPLES:: @@ -975,35 +1025,107 @@ def random_element(self): sage: P.random_element() Plane partition [[4, 3, 3], [4, 0, 0], [2, 0, 0], [0, 0, 0]] """ - def leq(thing1, thing2): - return all(thing1[i] <= thing2[i] for i in range(len(thing1))) - elem = [(i,j,k) for i in range(self._box[0]) for j in range(self._box[1]) - for k in range(self._box[2])] - myposet = Poset((elem, leq)) - R = myposet.random_order_ideal() - Z = [[0 for i in range(self._box[1])] for j in range(self._box[0])] - for C in R: +# def leq(thing1, thing2): +# return all(thing1[i] <= thing2[i] for i in range(len(thing1))) +# elem = [(i,j,k) for i in range(self._box[0]) for j in range(self._box[1]) +# for k in range(self._box[2])] +# myposet = Poset((elem, leq)) + a = self._box[0] + b = self._box[1] + c = self._box[2] + P = posets.ProductOfChains([a,b,c]) + I = P.random_order_ideal() + Z = [[0 for i in range(b)] for j in range(a)] + for C in I: Z[C[0]][C[1]] += 1 return self.element_class(self, Z, check=False) class PlanePartitions_n(PlanePartitions): - + """ + Plane partitions with a fixed number of boxes. + """ def __init__(self, n): - """ + r""" + Initializes the class of plane partitions with ``n`` boxes. + + .. WARNING:: + + Input is not checked; please use :class:`IncreasingTableaux` to + ensure the options are properly parsed. + TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + + sage: PP = PlanePartitions(4) + sage: type(PP) + sage: TestSuite(PP).run() """ super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) self._n = n def _repr_(self): - return " Totally Symmetric Plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + """ + TESTS:: + + sage: PlanePartitions(3) + Plane partitions of size 3 + """ + return "Plane partitions of size {}".format(self._n) + + def __iter__(self): + from sage.combinat.partition import Partitions, Partition + def PP_first_row_iter(n, la): + m = n-sum(la) + if m < 0: + yield + return + if m==0: + yield [la] + return + for k in range(m,0,-1): + for mu in P_in_shape_iter(k,la): + if mu is not None: + for PP in PP_first_row_iter(m, mu): + if PP is not None: + yield [la] + PP + + + def P_in_shape_iter(n, la): + if n<0 or sum(la)=n: + yield [n] + return + else: + yield + return + if sum(la)==n: + yield la + return + for mu_0 in range(min(n,la[0]),0,-1): + new_la = [min(mu_0,la[i]) for i in range(1,len(la))] + for mu in P_in_shape_iter(n-mu_0, new_la): + if mu is not None: + yield [mu_0]+mu + n = self._n + if n==0: + yield PlanePartition([]) + return + + for m in range(n,0,-1): + for la in Partitions(m): + for a in PP_first_row_iter(n,la): + yield a + + @@ -1035,7 +1157,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return " Totally Symmetric Plane partitions inside a {} x {} x {} box".format( + return "Totally Symmetric Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) class PlanePartitions_SPP(PlanePartitions): @@ -1065,7 +1187,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return " Symmetric Plane partitions inside a {} x {} x {} box".format( + return "Symmetric Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) def __iter__(self): @@ -1152,7 +1274,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return " Cyclically Symmetric Plane partitions inside a {} x {} x {} box".format( + return "Cyclically Symmetric Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) def __iter__(self): @@ -1247,14 +1369,14 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return " Self Complementary Plane partitions inside a {} x {} x {} box".format( + return "Self Complementary Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) -class PlanePartitions_TSSCPP(PlanePartitions_all): +class PlanePartitions_TSSCPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): @@ -1283,7 +1405,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return " Totally Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( + return "Totally Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1425,7 +1547,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return " Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( + return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1456,6 +1578,6 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return " Cyclically Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( + return "Cyclically Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) From d010cc99b497765a5680a0bfeb8384e7f4f20e1d Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 09:47:31 -0500 Subject: [PATCH 09/74] Output of fixed size iterator needes element constructor --- src/sage/combinat/plane_partition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index c050b1f6f48..899ff827a1a 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1123,7 +1123,7 @@ def P_in_shape_iter(n, la): for m in range(n,0,-1): for la in Partitions(m): for a in PP_first_row_iter(n,la): - yield a + yield PlanePartition(a) From f1b90f07a01781c94d91881df09ef3ff8d72d492 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 10:23:56 -0500 Subject: [PATCH 10/74] Added cardinality method for fixed size using recurrence relation --- src/sage/combinat/plane_partition.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 899ff827a1a..62fc4a91d0c 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -38,6 +38,7 @@ from sage.rings.integer import Integer from sage.misc.all import prod from sage.combinat.tableau import Tableau +from sage.arith.misc import Sigma @@ -1125,7 +1126,18 @@ def P_in_shape_iter(n, la): for a in PP_first_row_iter(n,la): yield PlanePartition(a) - + def cardinality(self): +# def PPn(n): +# if n==0: +# return 1 +# return sum(PPn(n-k)*Sigma()(k,2) for k in range(1,n+1))/n +# return(PPn(self._n)) + PPn = [1] + for i in range(1,1+self._n): + nextPPn = sum(PPn[i-k]*Sigma()(k,2) for k in range(1,i+1))/i + PPn.append(nextPPn) + return(PPn[-1]) + From 6213c366616b92f88bd4c3c55c3357f835907b30 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 10:24:16 -0500 Subject: [PATCH 11/74] Added cardinality method for fixed size using recurrence relation --- src/sage/combinat/plane_partition.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 62fc4a91d0c..73b343489ba 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1127,11 +1127,19 @@ def P_in_shape_iter(n, la): yield PlanePartition(a) def cardinality(self): -# def PPn(n): -# if n==0: -# return 1 -# return sum(PPn(n-k)*Sigma()(k,2) for k in range(1,n+1))/n -# return(PPn(self._n)) + r""" + Return the number of plane partitions with ``n`` boxes. + + Calculated using the recurrence relation + + ..MATH: + + PL(n) = \sum_{k=1}^n PL(n-k)\sigma_2(k) + + where ``\sigma_k(n)`` is the sum of the kth powers of + divisors of n. + + """ PPn = [1] for i in range(1,1+self._n): nextPPn = sum(PPn[i-k]*Sigma()(k,2) for k in range(1,i+1))/i From 11903983c6bebf04be7f507ba9de92f5ead05788 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 11:21:55 -0500 Subject: [PATCH 12/74] Added skeleton of missing classes, organized them in standard order --- src/sage/combinat/plane_partition.py | 322 +++++++++++++++++++-------- 1 file changed, 227 insertions(+), 95 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 73b343489ba..8650c38e480 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -765,20 +765,26 @@ def __classcall_private__(cls, *args, **kwds): box_size = args[0] if symmetry == None: return PlanePartitions_box(box_size) - elif symmetry == 'TSPP': - return PlanePartitions_TSPP(box_size) elif symmetry == 'SPP': return PlanePartitions_SPP(box_size) elif symmetry == 'CSPP': return PlanePartitions_CSPP(box_size) - elif symmetry == 'TSSCPP': - return PlanePartitions_TSSCPP(box_size) + elif symmetry == 'TSPP': + return PlanePartitions_TSPP(box_size) + elif symmetry == 'SCPP': + return PlanePartitions_SCPP(box_size) + elif symmetry == 'TCPP': + return PlanePartitions_TCPP(box_size) + elif symmetry == 'SSCPP': + return PlanePartitions_SSCPP(box_size) elif symmetry == 'CSTCPP': return PlanePartitions_CSTCPP(box_size) elif symmetry == 'CSSCPP': return PlanePartitions_CSSCPP(box_size) + elif symmetry == 'TSSCPP': + return PlanePartitions_TSSCPP(box_size) else: - raise ValueError("invalid symmetry class option; must be None, 'TSPP', 'SPP', 'CSPP', or 'TSCCPP' ") + raise ValueError("invalid symmetry class option; must be None, 'SPP', 'CSPP', 'TSPP', 'SCPP', 'TCPP', 'SSCPP', 'CSTCPP', 'CSSCPP', or 'TSSCPP' ") Element = PlanePartition @@ -1146,39 +1152,13 @@ def cardinality(self): PPn.append(nextPPn) return(PPn[-1]) +#Symmetry classes are enumerated and labelled in order as in Proofs and +#Confirmations/Stanley (with all plane partitions being the first class -class PlanePartitions_TSPP(PlanePartitions): - - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) - sage: P1 is P2 - True - """ - return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) - sage: TestSuite(PP).run() - """ - super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size - - def _repr_(self): - return "Totally Symmetric Plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) +#Class 2 class PlanePartitions_SPP(PlanePartitions): @@ -1266,6 +1246,7 @@ def componentwise_comparer(thing1,thing2): current += 1 +#Class 3 class PlanePartitions_CSPP(PlanePartitions): @@ -1362,6 +1343,43 @@ def componentwise_comparer2(thing1,thing2): current += 1 +#Class 4 + + +class PlanePartitions_TSPP(PlanePartitions): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) + self._box=box_size + + def _repr_(self): + return "Totally Symmetric Plane Partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + + + + class PlanePartitions_SCPP(PlanePartitions): @staticmethod @@ -1389,12 +1407,186 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Self Complementary Plane partitions inside a {} x {} x {} box".format( + return "Self-Complementary Plane Partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) +#Class 5 + +class PlanePartitions_SCPP(PlanePartitions): + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("box sides cannot all be odd") + super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box=box_size + + def _repr_(self): + return "Self-Complementary Plane Partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + +#Class 6 + +class PlanePartitions_TCPP(PlanePartitions): + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_TCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("box sides cannot all be odd") + super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box=box_size + + def _repr_(self): + return "Transpose Complement Plane Partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + +#Class 7 + +class PlanePartitions_SSCPP(PlanePartitions): + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_SSCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("box sides cannot all be odd") + super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box=box_size + + def _repr_(self): + return "Symmetric Self-Complementary Plane Partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + +#Class 8 + +class PlanePartitions_CSTCPP(PlanePartitions): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box=box_size + + def _repr_(self): + return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + +#Class 9 + + +class PlanePartitions_CSSCPP(PlanePartitions): + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2)) + sage: P2 = PlanePartitions([4,3,2]) + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: TestSuite(PP).run() + """ + super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box=box_size + + def _repr_(self): + return "Cyclically Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + + + + + + + + +#Class 10 class PlanePartitions_TSSCPP(PlanePartitions): @@ -1540,64 +1732,4 @@ def componentwise_comparer(thing1,thing2): yield self.element_class(self, matrixList[current]) current += 1 -class PlanePartitions_CSTCPP(PlanePartitions): - - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) - sage: TestSuite(PP).run() - """ - super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size - - def _repr_(self): - return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - -class PlanePartitions_CSSCPP(PlanePartitions): - - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) - sage: TestSuite(PP).run() - """ - super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size - - def _repr_(self): - return "Cyclically Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) From b29227724fedb22173e7f64ce1995167cd908162 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 11:27:14 -0500 Subject: [PATCH 13/74] changed repr methods to not all caps --- src/sage/combinat/plane_partition.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 8650c38e480..d4f955c410b 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1083,7 +1083,7 @@ def _repr_(self): return "Plane partitions of size {}".format(self._n) def __iter__(self): - from sage.combinat.partition import Partitions, Partition + from sage.combinat.partition import Partitions def PP_first_row_iter(n, la): m = n-sum(la) if m < 0: @@ -1153,7 +1153,7 @@ def cardinality(self): return(PPn[-1]) #Symmetry classes are enumerated and labelled in order as in Proofs and -#Confirmations/Stanley (with all plane partitions being the first class +#Confirmations/Stanley (with all plane partitions being the first class) @@ -1187,7 +1187,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Symmetric Plane partitions inside a {} x {} x {} box".format( + return "Symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) def __iter__(self): @@ -1275,7 +1275,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Cyclically Symmetric Plane partitions inside a {} x {} x {} box".format( + return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) def __iter__(self): @@ -1373,7 +1373,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Totally Symmetric Plane Partitions inside a {} x {} x {} box".format( + return "Transpose symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1407,7 +1407,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Self-Complementary Plane Partitions inside a {} x {} x {} box".format( + return "Self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1443,7 +1443,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Self-Complementary Plane Partitions inside a {} x {} x {} box".format( + return "Self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1477,7 +1477,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Transpose Complement Plane Partitions inside a {} x {} x {} box".format( + return "Transpose complement plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) #Class 7 @@ -1510,7 +1510,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Symmetric Self-Complementary Plane Partitions inside a {} x {} x {} box".format( + return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) #Class 8 @@ -1575,17 +1575,13 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Cyclically Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( + return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - - - - #Class 10 class PlanePartitions_TSSCPP(PlanePartitions): @@ -1617,7 +1613,7 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Totally Symmetric Self-Complementary Plane partitions inside a {} x {} x {} box".format( + return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) From e843a5268225583cbdfc5fdeac8a44c568f600f1 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 11:51:41 -0500 Subject: [PATCH 14/74] cleaned up iterator code some, fixed minor category issue --- src/sage/combinat/plane_partition.py | 49 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index d4f955c410b..882c60cace9 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1271,7 +1271,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_CSPP, self).__init__() + super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size def _repr_(self): @@ -1295,6 +1295,9 @@ def componentwise_comparer2(thing1,thing2): a=self._box[0] b=self._box[1] c=self._box[2] + cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) + cmp2 = lambda x,y : cmp(x,y) or cmp(x,(y[2],y[0],y[1])) or cmp(x,(y[1],y[2],y[0])) + pl = [] for x in range(0,a): for y in range(0, b): @@ -1302,7 +1305,8 @@ def componentwise_comparer2(thing1,thing2): if y <= z and (x != z or y == x): pl.append((x,y,z)) - pocp = Poset((pl,componentwise_comparer2)) +# pocp = Poset((pl,componentwise_comparer2)) + pocp = Poset((pl, cmp2)) matrixList = [] #list of all PlaneParitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with paramaters (a,b,c) for acl in pocp.antichains_iterator(): @@ -1332,15 +1336,16 @@ def componentwise_comparer2(thing1,thing2): if j < c-1: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) + yield self.element_class(self, ppMatrix) - matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions +# matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions - matrixList.sort() +# matrixList.sort() - current = 0 - while current < len(matrixList): - yield self.element_class(self, matrixList[current]) - current += 1 +# current = 0 +# while current < len(matrixList): +# yield self.element_class(self, matrixList[current]) +# current += 1 #Class 4 @@ -1403,7 +1408,7 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ - super(PlanePartitions_SCPP, self).__init__() + super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size def _repr_(self): @@ -1618,11 +1623,11 @@ def _repr_(self): def __iter__(self): - def componentwise_comparer(thing1,thing2): - if len(thing1) == len(thing2): - if all(thing1[i] <= thing2[i] for i in range(len(thing1))): - return True - return False +# def componentwise_comparer(thing1,thing2): +# if len(thing1) == len(thing2): +# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): +# return True +# return False a=self._box[0] b=self._box[1] c=self._box[2] @@ -1637,9 +1642,11 @@ def componentwise_comparer(thing1,thing2): if z <= n/2 - 2 - y: pl.append((x,y,z)) - pocp = Poset((pl,componentwise_comparer)) +# pocp = Poset((pl,componentwise_comparer)) + cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) + pocp = Poset((pl,cmp)) - matrixList = [] #list of all PlaneParitions with parameters(a,b,c) +# matrixList = [] #list of all PlaneParitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with paramaters (a,b,c) for acl in pocp.antichains_iterator(): #ac format ex: [x,y,z] @@ -1718,14 +1725,6 @@ def componentwise_comparer(thing1,thing2): for i in range(n/2): for j in range(n/2): ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] - - matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions - - matrixList.sort() - - current = 0 - while current < len(matrixList): - yield self.element_class(self, matrixList[current]) - current += 1 + yield self.element_class(self, ppMatrix) From 507a8f61c29f4f457502230baa6e6b66bc1c9553 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 11:58:00 -0500 Subject: [PATCH 15/74] More minor iterator fixes --- src/sage/combinat/plane_partition.py | 52 +++++++++++++++------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 882c60cace9..987bd5e65c6 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1191,11 +1191,12 @@ def _repr_(self): self._box[0], self._box[1], self._box[2]) def __iter__(self): - def componentwise_comparer(thing1,thing2): - if len(thing1) == len(thing2): - if all(thing1[i] <= thing2[i] for i in range(len(thing1))): - return True - return False +# def componentwise_comparer(thing1,thing2): +# if len(thing1) == len(thing2): +# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): +# return True +# return False + cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) a=self._box[0] b=self._box[1] c=self._box[2] @@ -1207,7 +1208,7 @@ def componentwise_comparer(thing1,thing2): pl.append((x,y,z)) - pocp = Poset((pl,componentwise_comparer)) + pocp = Poset((pl,cmp)) matrixList = [] #list of all PlaneParitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with paramaters (a,b,c) @@ -1237,13 +1238,14 @@ def componentwise_comparer(thing1,thing2): ppMatrix[i][j] = max(iValue,jValue) elif j>i: ppMatrix[i][j] = ppMatrix[j][i] + yield self.element_class(self, ppMatrix) - matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions - matrixList.sort() - current = 0 - while current < len(matrixList): - yield self.element_class(self, matrixList[current]) - current += 1 +# matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions +# matrixList.sort() +# current = 0 +# while current < len(matrixList): +# yield self.element_class(self, matrixList[current]) +# current += 1 #Class 3 @@ -1279,19 +1281,19 @@ def _repr_(self): self._box[0], self._box[1], self._box[2]) def __iter__(self): - def componentwise_comparer(thing1,thing2): - if len(thing1) == len(thing2): - if all(thing1[i] <= thing2[i] for i in range(len(thing1))): - return True - return False - def componentwise_comparer2(thing1,thing2): - x = thing2[0] - y = thing2[1] - z = thing2[2] - - if componentwise_comparer(thing1,(x,y,z)) or componentwise_comparer(thing1,(z,x,y)) or componentwise_comparer(thing1,(y,z,x)): - return True - return False +# def componentwise_comparer(thing1,thing2): +# if len(thing1) == len(thing2): +# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): +# return True +# return False +# def componentwise_comparer2(thing1,thing2): +# x = thing2[0] +# y = thing2[1] +# z = thing2[2] + +# if componentwise_comparer(thing1,(x,y,z)) or componentwise_comparer(thing1,(z,x,y)) or componentwise_comparer(thing1,(y,z,x)): +# return True +# return False a=self._box[0] b=self._box[1] c=self._box[2] From d91a33314ec4ed608d6ccef38f385c7fd146b337 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 26 Jul 2019 12:29:47 -0500 Subject: [PATCH 16/74] more changes --- src/sage/combinat/plane_partition.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 987bd5e65c6..c667ac07114 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1190,6 +1190,10 @@ def _repr_(self): return "Symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __contains__(self, x): + return PlanePartitions.__contains__(self, x) and x.is_SPP() + + def __iter__(self): # def componentwise_comparer(thing1,thing2): # if len(thing1) == len(thing2): @@ -1625,11 +1629,11 @@ def _repr_(self): def __iter__(self): -# def componentwise_comparer(thing1,thing2): -# if len(thing1) == len(thing2): -# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): -# return True -# return False + def componentwise_comparer(thing1,thing2): + if len(thing1) == len(thing2): + if all(thing1[i] <= thing2[i] for i in range(len(thing1))): + return True + return False a=self._box[0] b=self._box[1] c=self._box[2] @@ -1644,9 +1648,9 @@ def __iter__(self): if z <= n/2 - 2 - y: pl.append((x,y,z)) -# pocp = Poset((pl,componentwise_comparer)) + pocp = Poset((pl,componentwise_comparer)) cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) - pocp = Poset((pl,cmp)) +# pocp = Poset((pl,cmp)) # matrixList = [] #list of all PlaneParitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with paramaters (a,b,c) From 4aefa3934f4e6a5b0180cbaae6b3bb06be977aac Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 1 Oct 2019 09:33:28 -0500 Subject: [PATCH 17/74] Fixed SPP iterator and cardinality methods --- src/sage/combinat/plane_partition.py | 134 +++++++++++++++++++-------- 1 file changed, 94 insertions(+), 40 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 7a3509295ec..12bf663bf68 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1199,8 +1199,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((4,3,2), symmetry='SPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='SPP') sage: P1 is P2 True """ @@ -1210,7 +1210,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([3,3,3], symmetry='SPP') sage: TestSuite(PP).run() """ super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) @@ -1225,61 +1225,115 @@ def __contains__(self, x): def __iter__(self): -# def componentwise_comparer(thing1,thing2): -# if len(thing1) == len(thing2): -# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): -# return True -# return False - cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) + #Construct poset whose order ideals are naturally in bijection + #with symmetric plane partitions + cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) a=self._box[0] b=self._box[1] c=self._box[2] pl = [] for x in range(0,a): - for y in range(0, b): - for z in range(0,c): - if z <= y: - pl.append((x,y,z)) - - + for y in range(0,x+1): + for z in range(0,c): + pl.append((x,y,z)) pocp = Poset((pl,cmp)) - - matrixList = [] #list of all PlaneParitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with paramaters (a,b,c) + #Iterate over antichains in this poset for acl in pocp.antichains_iterator(): - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - #ac format ex: [x,y,z] - #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) + #Initialize an empty plane partition + ppMatrix = [[0] * (a) for i in range(b)] + #Antichain indicates where the 'corners' will be in the + #plane partition for ac in acl: - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix[y][z] = (x+1) - - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format - if acl != []: - for i in range(b): - i = b-(i+1) - for j in range(c): - j = c-(j+1) + x=ac[0] + y=ac[1] + z=ac[2] + ppMatrix[x][y] = (z+1) + #Fill out the rest of the plane partition using symmetry and the + #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) + if acl!= []: + for i in range(a): + i = a-(i+1) + for j in range(b): + j = b-(j+1) if (ppMatrix[i][j] == 0) and i>=j: iValue = 0 jValue = 0 - if i < b-1: + if i < a-1: iValue = ppMatrix[i+1][j] - if j < c-1: + if j < b-1: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) elif j>i: ppMatrix[i][j] = ppMatrix[j][i] yield self.element_class(self, ppMatrix) -# matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions -# matrixList.sort() -# current = 0 -# while current < len(matrixList): -# yield self.element_class(self, matrixList[current]) -# current += 1 + + +# cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) +# a=self._box[0] +# b=self._box[1] +# c=self._box[2] +# pl = [] +# for x in range(0,a): +# for y in range(0, b): +# for z in range(0,c): +# if z <= y: +# pl.append((x,y,z)) +# pocp = Poset((pl,cmp)) +# #iterate through each antichain of product of chains poset with paramaters (a,b,c) +# for acl in pocp.antichains_iterator(): +# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] +# #ac format ex: [x,y,z] +# #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) +# for ac in acl: +# x = ac[0] +# y = ac[1] +# z = ac[2] +# ppMatrix[y][z] = (x+1) + +# #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format +# if acl != []: +# for i in range(b): +# i = b-(i+1) +# for j in range(c): +# j = c-(j+1) +# if (ppMatrix[i][j] == 0) and i>=j: +# iValue = 0 +# jValue = 0 +# if i < b-1: +# iValue = ppMatrix[i+1][j] +# if j < c-1: +# jValue = ppMatrix[i][j+1] +# ppMatrix[i][j] = max(iValue,jValue) +# elif j>i: +# ppMatrix[i][j] = ppMatrix[j][i] +# yield self.element_class(self, ppMatrix) + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of symmetric plane partitions inside an `r \times r \times t` + box is equal to + + .. MATH:: + + \prod_{i=1}^{r} \frac{2*i + t - 1}{2*i - 1} * + \prod_{1 \leq i \leq j \leq r} \frac{i+j+t-1}{i+j-1} + + EXAMPLES:: + + sage: P = PlanePartitions((4,3,2), symmetry='SPP') + sage: P.cardinality() + 116424 + """ + A = self._box[0] + B = self._box[1] + C = self._box[2] + leftProduct = (prod( (2*i + C - 1) / (2*i - 1) for i in range(1,A+1))) + rightProduct = (prod( (i + j + C - 1) / (i + j - 1) for j in range(1, A+1) for i in range(1, j) )) + return leftProduct * rightProduct + #Class 3 From f220f3a45d6d786de81d460e8621a52cf3111960 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 1 Oct 2019 09:34:51 -0500 Subject: [PATCH 18/74] SPP cardinality doctest fix --- src/sage/combinat/plane_partition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 12bf663bf68..59bc86c481d 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1323,9 +1323,9 @@ def cardinality(self): EXAMPLES:: - sage: P = PlanePartitions((4,3,2), symmetry='SPP') + sage: P = PlanePartitions((3,3,2), symmetry='SPP') sage: P.cardinality() - 116424 + 35 """ A = self._box[0] B = self._box[1] From 1a7af8f157f46978284d1e61bac695957b98f0cb Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 1 Oct 2019 10:15:43 -0500 Subject: [PATCH 19/74] CSPP cardinality and other doc cleanup --- src/sage/combinat/plane_partition.py | 53 +++++++++++++++------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 59bc86c481d..35016f25a20 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1358,7 +1358,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') sage: TestSuite(PP).run() """ super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) @@ -1369,19 +1369,6 @@ def _repr_(self): self._box[0], self._box[1], self._box[2]) def __iter__(self): -# def componentwise_comparer(thing1,thing2): -# if len(thing1) == len(thing2): -# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): -# return True -# return False -# def componentwise_comparer2(thing1,thing2): -# x = thing2[0] -# y = thing2[1] -# z = thing2[2] - -# if componentwise_comparer(thing1,(x,y,z)) or componentwise_comparer(thing1,(z,x,y)) or componentwise_comparer(thing1,(y,z,x)): -# return True -# return False a=self._box[0] b=self._box[1] c=self._box[2] @@ -1394,14 +1381,12 @@ def __iter__(self): for z in range(x,c): if y <= z and (x != z or y == x): pl.append((x,y,z)) - -# pocp = Poset((pl,componentwise_comparer2)) pocp = Poset((pl, cmp2)) matrixList = [] #list of all PlaneParitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with paramaters (a,b,c) for acl in pocp.antichains_iterator(): - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - + ppMatrix = [[0] * (c) for i in range(b)] + #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] #ac format ex: [x,y,z] for ac in acl: x = ac[0] @@ -1412,7 +1397,9 @@ def __iter__(self): ppMatrix[x][y] = (z+1) - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + #for each value in current antichain, fill in the rest of the + #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is + #now in plane partition format if acl != []: for i in range(b): i = b-(i+1) @@ -1428,14 +1415,30 @@ def __iter__(self): ppMatrix[i][j] = max(iValue,jValue) yield self.element_class(self, ppMatrix) -# matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions + def cardinality(self): + r""" + Return the cardinality of ``self``. -# matrixList.sort() + The number of cyclically symmetric plane partitions inside an + `r \times r \times r` box is equal to -# current = 0 -# while current < len(matrixList): -# yield self.element_class(self, matrixList[current]) -# current += 1 + .. MATH:: + + \prod_{i=1}^{r} \frac{3*i - 1}{3*i - 2} * + \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{2*i+j-1} + + EXAMPLES:: + + sage: P = PlanePartitions((4,4,4), symmetry='CSPP') + sage: P.cardinality() + 132 + """ + A = self._box[0] + B = self._box[1] + C = self._box[2] + 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 numerator/denominator #Class 4 From 85a4c326e12ccbc4dd8cfefc1c6826513bcf5699 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 1 Oct 2019 16:24:27 -0500 Subject: [PATCH 20/74] Refactored plane partitions in a box with to_poset method to be used in other classes --- src/sage/combinat/plane_partition.py | 205 ++++++++++++++++++++++----- 1 file changed, 166 insertions(+), 39 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 35016f25a20..652b452710c 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -930,7 +930,61 @@ def __repr__(self): return "Plane partitions inside a %s x %s x %s box" % (self._box[0], self._box[1], self._box[2]) # return "Plane partitions inside a box" + def to_poset(self): + r""" + Returns the product of three chains poset, whose order ideals are + naturally in bijection with plane partitions inside a box. + """ + a=self._box[0] + b=self._box[1] + c=self._box[2] + return posets.ProductOfChains([a,b,c]) + def from_order_ideal(self, I): + r""" + Return the plane partition corresponding to an order ideal in the + poset given in (LINK) to_poset(). + + Note: input may not be checked ? Optional check parameter if too much overhead? + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def from_antichain(self, A): + r""" + Return the plane partition corresponding to an antichain in the poset + given in (LINK) to_poset(). + + Note: input may not be checked? Optional parameter if too much overhead? + """ + a = self._box[0] + b = self._box[1] + c = self._box[2] + ppMatrix = [[0] * (a) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + + #ac format ex: [x,y,z] + #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) + for ac in A: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][x] = (z+1) + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if A != []: + for i in range(a): + i = a-(i+1) + for j in range(b): + j = b-(j+1) + if (ppMatrix[j][i] == 0): + iValue = 0 + jValue = 0 + if i < a-1: + iValue = ppMatrix[j][i+1] + if j < b-1: + jValue = ppMatrix[j+1][i] + ppMatrix[j][i] = max(iValue,jValue) + return self.element_class(self, ppMatrix) + def __iter__(self): """ @@ -969,35 +1023,36 @@ def __iter__(self): # pocp = product_of_chains_poset([a,b,c]) pocp = posets.ProductOfChains([a,b,c]) - matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + matrixList = [] #list of all PlanePartitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with paramaters (a,b,c) + #iterate through each antichain of product of chains poset with parameters (a,b,c) for acl in pocp.antichains_iterator(): - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] +# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - #ac format ex: [x,y,z] - #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) - for ac in acl: - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix[y][z] = (x+1) +# #ac format ex: [x,y,z] +# #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) +# for ac in acl: +# x = ac[0] +# y = ac[1] +# z = ac[2] +# ppMatrix[y][z] = (x+1) - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format - if acl != []: - for i in range(b): - i = b-(i+1) - for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): - iValue = 0 - jValue = 0 - if i < b-1: - iValue = ppMatrix[i+1][j] - if j < c-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - yield self.element_class(self, ppMatrix) +# #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format +# if acl != []: +# for i in range(b): +# i = b-(i+1) +# for j in range(c): +# j = c-(j+1) +# if (ppMatrix[i][j] == 0): +# iValue = 0 +# jValue = 0 +# if i < b-1: +# iValue = ppMatrix[i+1][j] +# if j < c-1: +# jValue = ppMatrix[i][j+1] +# ppMatrix[i][j] = max(iValue,jValue) +# yield self.element_class(self, ppMatrix) + yield self.from_antichain(acl) # matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions @@ -1067,14 +1122,15 @@ def random_element(self): # elem = [(i,j,k) for i in range(self._box[0]) for j in range(self._box[1]) # for k in range(self._box[2])] # myposet = Poset((elem, leq)) - a = self._box[0] - b = self._box[1] - c = self._box[2] - P = posets.ProductOfChains([a,b,c]) - I = P.random_order_ideal() - Z = [[0 for i in range(b)] for j in range(a)] - for C in I: - Z[C[0]][C[1]] += 1 +# a = self._box[0] +# b = self._box[1] +# c = self._box[2] +# P = posets.ProductOfChains([a,b,c]) +# I = P.random_order_ideal() +# Z = [[0 for i in range(b)] for j in range(a)] +# for C in I: +# Z[C[0]][C[1]] += 1 + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) @@ -1090,8 +1146,8 @@ def __init__(self, n): .. WARNING:: - Input is not checked; please use :class:`IncreasingTableaux` to - ensure the options are properly parsed. + Input is not checked; please use :class:`PlanePartitions` to + ensure the options are properly parsed. (CHECK: does this make sense?) TESTS:: @@ -1347,8 +1403,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((4,3,2), symmetry='CSPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='CSPP') sage: P1 is P2 True """ @@ -1453,8 +1509,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((4,3,2), symmetry='TSPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='TSPP') sage: P1 is P2 True """ @@ -1474,7 +1530,78 @@ def _repr_(self): return "Transpose symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __iter__(self): + cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) + pl = [] + for x in range(0,a): + for y in range(x, b): + for z in range(y,c): + pl.append((x,y,z)) + + myposet = Poset((pl,cmp)) + + R = myposet.random_order_ideal() + acl = R + + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + + #ac format ex: [x,y,z] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) #x,y,z + ppMatrix[z][x] = (y+1) #y,z,x + ppMatrix[x][y] = (z+1) #z,x,y + + ppMatrix[z][y] = (x+1) #x,z,y + ppMatrix[x][z] = (y+1) #y,x,z + ppMatrix[y][x] = (z+1) #z,y,x + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + + return PlanePartition(ppMatrix) + + + + + + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of transpose symmetric plane partitions inside an + `r \times r \times r` box is equal to + + .. MATH:: + + \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{i+2*j-2} + + EXAMPLES:: + + sage: P = PlanePartitions((4,4,4), symmetry='TSPP') + sage: P.cardinality() + 66 + """ + A = self._box[0] + B = self._box[1] + C = self._box[2] + return (prod((i + j + A - 1) / (i + 2*j - 2) for j in range(1,A+1) for i in range(1,j+1) )) From 34fa0a3ac966398178d823ea67aa854860b7930c Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 1 Oct 2019 17:22:10 -0500 Subject: [PATCH 21/74] Refactored with to_poset method in SPP --- src/sage/combinat/plane_partition.py | 149 +++++++++++++++++++++------ 1 file changed, 115 insertions(+), 34 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 652b452710c..9e2a6aacbb2 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1026,7 +1026,7 @@ def __iter__(self): matrixList = [] #list of all PlanePartitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with parameters (a,b,c) - for acl in pocp.antichains_iterator(): + for acl in self.to_poset().antichains_iterator(): # ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] # #ac format ex: [x,y,z] @@ -1280,48 +1280,111 @@ def __contains__(self, x): return PlanePartitions.__contains__(self, x) and x.is_SPP() - def __iter__(self): - #Construct poset whose order ideals are naturally in bijection - #with symmetric plane partitions - cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) + def to_poset(self): + r""" + Returns a poset whose order ideals are in bijection with + symmetric plane partitions. + """ a=self._box[0] - b=self._box[1] + b=self._box[1] c=self._box[2] pl = [] + cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) for x in range(0,a): for y in range(0,x+1): for z in range(0,c): pl.append((x,y,z)) - pocp = Poset((pl,cmp)) - #Iterate over antichains in this poset - for acl in pocp.antichains_iterator(): - #Initialize an empty plane partition - ppMatrix = [[0] * (a) for i in range(b)] - #Antichain indicates where the 'corners' will be in the - #plane partition - for ac in acl: - x=ac[0] - y=ac[1] - z=ac[2] - ppMatrix[x][y] = (z+1) - #Fill out the rest of the plane partition using symmetry and the - #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) - if acl!= []: + return Poset((pl,cmp)) + + def from_order_ideal(self, I): + r""" + Return the plane partition corresponding to an order ideal in the + poset given in (LINK) to_poset(). + + Note: input may not be checked ? Optional check parameter if too much overhead? + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def from_antichain(self, A): + r""" + Return the plane partition corresponding to an antichain in the poset + given in (LINK) to_poset(). + + Note: input may not be checked? Optional parameter if too much overhead? + """ + #Initialize an empty plane partition + a=self._box[0] + b=self._box[1] + c=self._box[2] + ppMatrix = [[0] * (a) for i in range(b)] + #Antichain indicates where the 'corners' will be in the + #plane partition + for ac in A: + x=ac[0] + y=ac[1] + z=ac[2] + ppMatrix[y][x] = (z+1) + #Fill out the rest of the plane partition using symmetry and the + #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) + if A!= []: + for j in range(b): + j = b-(j+1) for i in range(a): i = a-(i+1) - for j in range(b): - j = b-(j+1) - if (ppMatrix[i][j] == 0) and i>=j: - iValue = 0 - jValue = 0 - if i < a-1: - iValue = ppMatrix[i+1][j] - if j < b-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - elif j>i: - ppMatrix[i][j] = ppMatrix[j][i] - yield self.element_class(self, ppMatrix) + if (ppMatrix[j][i] == 0) and j>=i: + iValue = 0 + jValue = 0 + if i < a-1: + iValue = ppMatrix[j][i+1] + if j < b-1: + jValue = ppMatrix[j+1][i] + ppMatrix[j][i] = max(iValue,jValue) + elif i>j: + ppMatrix[j][i] = ppMatrix[i][j] + return self.element_class(self, ppMatrix) + + def __iter__(self): + #Construct poset whose order ideals are naturally in bijection + #with symmetric plane partitions +# cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) +# a=self._box[0] +# b=self._box[1] +# c=self._box[2] +# pl = [] +# for x in range(0,a): +# for y in range(0,x+1): +# for z in range(0,c): +# pl.append((x,y,z)) +# pocp = Poset((pl,cmp)) + #Iterate over antichains in this poset + for acl in self.to_poset().antichains_iterator(): +# #Initialize an empty plane partition +# ppMatrix = [[0] * (a) for i in range(b)] +# #Antichain indicates where the 'corners' will be in the +# #plane partition +# for ac in acl: +# x=ac[0] +# y=ac[1] +# z=ac[2] +# ppMatrix[x][y] = (z+1) +# #Fill out the rest of the plane partition using symmetry and the +# #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) +# if acl!= []: +# for i in range(a): +# i = a-(i+1) +# for j in range(b): +# j = b-(j+1) +# if (ppMatrix[i][j] == 0) and i>=j: +# iValue = 0 +# jValue = 0 +# if i < a-1: +# iValue = ppMatrix[i+1][j] +# if j < b-1: +# jValue = ppMatrix[i][j+1] +# ppMatrix[i][j] = max(iValue,jValue) +# elif j>i: +# ppMatrix[i][j] = ppMatrix[j][i] + yield self.from_antichain(acl) @@ -1390,7 +1453,25 @@ def cardinality(self): rightProduct = (prod( (i + j + C - 1) / (i + j - 1) for j in range(1, A+1) for i in range(1, j) )) return leftProduct * rightProduct + def random_element(self): + r""" + Return a uniformly random element of ``self``. + + ALGORITHM: + + This uses the + :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` + method and the natural bijection between symmetric plane partitions + and antichains in an associated poset. (FIX EXAMPLES) + + EXAMPLES:: + sage: P = PlanePartitions((4,3,5)) + sage: P.random_element() + Plane partition [[4, 3, 3], [4, 0, 0], [2, 0, 0], [0, 0, 0]] + """ + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) + return self.element_class(self, Z, check=False) #Class 3 From acc2bce6978465972611777c85b657f37f4ff5e4 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 2 Oct 2019 19:13:06 -0500 Subject: [PATCH 22/74] Refactored with to_poset method in CSPP, mostly --- src/sage/combinat/plane_partition.py | 116 +++++++++++++++++++-------- 1 file changed, 82 insertions(+), 34 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 9e2a6aacbb2..7565b73422f 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1505,52 +1505,100 @@ def _repr_(self): return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def to_poset(self): + """ + MAKE SURE DOC EXPLICITLY DESCRIBES WHAT FUNDAMENTAL DOMAIN LOOKS LIKE + """ a=self._box[0] b=self._box[1] c=self._box[2] cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) cmp2 = lambda x,y : cmp(x,y) or cmp(x,(y[2],y[0],y[1])) or cmp(x,(y[1],y[2],y[0])) - pl = [] for x in range(0,a): for y in range(0, b): for z in range(x,c): if y <= z and (x != z or y == x): pl.append((x,y,z)) - pocp = Poset((pl, cmp2)) - matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + return Poset((pl, cmp2)) + + def from_antichain(self): + ppMatrix = [[0] * (c) for i in range(b)] + #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + #ac format ex: [x,y,z] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) + ppMatrix[z][x] = (y+1) + ppMatrix[x][y] = (z+1) + + + #for each value in current antichain, fill in the rest of the + #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is + #now in plane partition format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + return self.element_class(self, ppMatrix) + + def __iter__(self): +# a=self._box[0] +# b=self._box[1] +# c=self._box[2] +# cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) +# cmp2 = lambda x,y : cmp(x,y) or cmp(x,(y[2],y[0],y[1])) or cmp(x,(y[1],y[2],y[0])) + +# pl = [] +# for x in range(0,a): +# for y in range(0, b): +# for z in range(x,c): +# if y <= z and (x != z or y == x): +# pl.append((x,y,z)) +# pocp = Poset((pl, cmp2)) +# matrixList = [] #list of all PlaneParitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with paramaters (a,b,c) - for acl in pocp.antichains_iterator(): - ppMatrix = [[0] * (c) for i in range(b)] - #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - #ac format ex: [x,y,z] - for ac in acl: - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix[y][z] = (x+1) - ppMatrix[z][x] = (y+1) - ppMatrix[x][y] = (z+1) - - - #for each value in current antichain, fill in the rest of the - #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is - #now in plane partition format - if acl != []: - for i in range(b): - i = b-(i+1) - for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): - iValue = 0 - jValue = 0 - if i < b-1: - iValue = ppMatrix[i+1][j] - if j < c-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - yield self.element_class(self, ppMatrix) + for acl in self.to_poset().antichains_iterator(): +# ppMatrix = [[0] * (c) for i in range(b)] +# #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] +# #ac format ex: [x,y,z] +# for ac in acl: +# x = ac[0] +# y = ac[1] +# z = ac[2] +# ppMatrix[y][z] = (x+1) +# ppMatrix[z][x] = (y+1) +# ppMatrix[x][y] = (z+1) + + +# #for each value in current antichain, fill in the rest of the +# #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is +# #now in plane partition format +# if acl != []: +# for i in range(b): +# i = b-(i+1) +# for j in range(c): +# j = c-(j+1) +# if (ppMatrix[i][j] == 0): +# iValue = 0 +# jValue = 0 +# if i < b-1: +# iValue = ppMatrix[i+1][j] +# if j < c-1: +# jValue = ppMatrix[i][j+1] +# ppMatrix[i][j] = max(iValue,jValue) + yield self.from_antichain() def cardinality(self): r""" From 6ee2ac9d2a6e520c1e58107e5d5ce3e908d80404 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 3 Oct 2019 09:56:33 -0500 Subject: [PATCH 23/74] Refactored with to_poset method in TSPP, mostly --- src/sage/combinat/plane_partition.py | 96 +++++++++++++++++++++------- 1 file changed, 74 insertions(+), 22 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 7565b73422f..121839de0c1 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1551,7 +1551,16 @@ def from_antichain(self): if j < c-1: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) - return self.element_class(self, ppMatrix) + return self.element_class(self, ppMatrix) + + def from_order_ideal(self, I): + r""" + Return the plane partition corresponding to an order ideal in the + poset given in (LINK) to_poset(). + + Note: input may not be checked ? Optional check parameter if too much overhead? + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) def __iter__(self): # a=self._box[0] @@ -1649,7 +1658,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') sage: TestSuite(PP).run() """ super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) @@ -1659,33 +1668,26 @@ def _repr_(self): return "Transpose symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def to_poset(self): cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) pl = [] for x in range(0,a): for y in range(x, b): for z in range(y,c): pl.append((x,y,z)) + return Poset((pl,cmp)) - myposet = Poset((pl,cmp)) - - R = myposet.random_order_ideal() - acl = R - - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - - #ac format ex: [x,y,z] - for ac in acl: - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix[y][z] = (x+1) #x,y,z - ppMatrix[z][x] = (y+1) #y,z,x - ppMatrix[x][y] = (z+1) #z,x,y + def from_antichain(self): + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) #x,y,z + ppMatrix[z][x] = (y+1) #y,z,x + ppMatrix[x][y] = (z+1) #z,x,y - ppMatrix[z][y] = (x+1) #x,z,y - ppMatrix[x][z] = (y+1) #y,x,z - ppMatrix[y][x] = (z+1) #z,y,x + ppMatrix[z][y] = (x+1) #x,z,y + ppMatrix[x][z] = (y+1) #y,x,z + ppMatrix[y][x] = (z+1) #z,y,x #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format @@ -1702,8 +1704,58 @@ def __iter__(self): if j < c-1: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) + return self.element_class(self, ppMatrix) + + def random_element(self): + return self.to_poset().from_antichain(self.to_poset().random_antichain()) - return PlanePartition(ppMatrix) + def __iter__(self): + for A in self.to_poset().antichains_iterator(): + yield self.from_antichain(A) +# cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) +# pl = [] +# for x in range(0,a): +# for y in range(x, b): +# for z in range(y,c): +# pl.append((x,y,z)) + +# myposet = Poset((pl,cmp)) + +# R = myposet.random_order_ideal() +# acl = R + +# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + +# #ac format ex: [x,y,z] +# for ac in acl: +# x = ac[0] +# y = ac[1] +# z = ac[2] +# ppMatrix[y][z] = (x+1) #x,y,z +# ppMatrix[z][x] = (y+1) #y,z,x +# ppMatrix[x][y] = (z+1) #z,x,y + +# ppMatrix[z][y] = (x+1) #x,z,y +# ppMatrix[x][z] = (y+1) #y,x,z +# ppMatrix[y][x] = (z+1) #z,y,x + + +# #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format +# if acl != []: +# for i in range(b): +# i = b-(i+1) +# for j in range(c): +# j = c-(j+1) +# if (ppMatrix[i][j] == 0): +# iValue = 0 +# jValue = 0 +# if i < b-1: +# iValue = ppMatrix[i+1][j] +# if j < c-1: +# jValue = ppMatrix[i][j+1] +# ppMatrix[i][j] = max(iValue,jValue) + +# return PlanePartition(ppMatrix) From 2d5e451374409db4fa7cecf56c0046e2157a9439 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 3 Oct 2019 12:03:24 -0500 Subject: [PATCH 24/74] Refactored with to_poset method in TSPP, mostly --- src/sage/combinat/plane_partition.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 121839de0c1..0898e6407d7 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1681,6 +1681,7 @@ def from_antichain(self): x = ac[0] y = ac[1] z = ac[2] + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] ppMatrix[y][z] = (x+1) #x,y,z ppMatrix[z][x] = (y+1) #y,z,x ppMatrix[x][y] = (z+1) #z,x,y From 7c457f5b0d4d13f5febb85f1cd8a8bf4031261b9 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Mon, 7 Oct 2019 18:48:57 -0500 Subject: [PATCH 25/74] Refactored iterator for SCPP --- src/sage/combinat/plane_partition.py | 151 +++++++++++++++++++++------ 1 file changed, 121 insertions(+), 30 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 0898e6407d7..8939c796cdf 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -39,6 +39,7 @@ from sage.misc.all import prod from sage.combinat.tableau import Tableau from sage.arith.misc import Sigma +from sage.functions.other import floor, ceil @@ -1787,8 +1788,9 @@ def cardinality(self): -class PlanePartitions_SCPP(PlanePartitions): +#Class 5 +class PlanePartitions_SCPP(PlanePartitions): @staticmethod def __classcall_private__(cls, box_size): """ @@ -1796,8 +1798,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((4,3,2), symmetry='SCPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='SCPP') sage: P1 is P2 True """ @@ -1810,6 +1812,8 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) sage: TestSuite(PP).run() """ +# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): +# raise ValueError("box sides cannot all be odd") super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size @@ -1817,41 +1821,128 @@ def _repr_(self): return "Self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __iter__(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] + def Partitions_inside_lambda(la): + "Returns the list of partitions contained in la with the same number of parts including 0s." + if len(la)==0: + yield [] + return + LIST = [] + 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 for i in la] + return + def Partitions_inside_lambda_with_smallest_at_least_k(la,k): + "Returns the list of partitions contained in la with the smallest entry at least k" + if len(la)==0: + yield [] + return + if la[-1] < k: + yield + return + LIST = [] + for mu in Partitions_inside_lambda([la[i]-k for i in range(len(la))]): + yield ([mu[i]+k for i in range(len(la))]) + return + def possible_middle_row_for_b_odd(a,c): + "Returns the list of possible middle row for SCPP inside box(a,b,c) when b is odd" + if a*c % 2 == 1: + yield + return + LIST = [] + for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor(a/2))]): + nu = [c-mu[len(mu)-1-i] for i in range(len(mu))] + if a % 2 ==0: + la = nu + mu + else: + la = nu + [c/2] + mu + yield (la) + return -#Class 5 + def possible_middle_row_for_b_even(a,c): + "Returns the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" + LIST = [] + for mu in Partitions_inside_lambda([floor(c/2) for i in range((a+1)/2)]): + nu = [c-mu[len(mu)-1-i] for i in range(floor(a/2))] + for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu,mu[0]): + la = tau + mu + yield (la) + return -class PlanePartitions_SCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) - sage: P1 is P2 - True - """ - return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) + def PPs_with_first_row_la_and_with_k_rows(la,k): + "Returns PPs with first row la and with k rows in total" + if k == 0: + yield [] + return + if k == 1: + yield [la] + return + LIST = [] + 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) - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) - sage: TestSuite(PP).run() - """ - if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("box sides cannot all be odd") - super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + return - def _repr_(self): - return "Self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + def complement(PP,c): + "Returns the complement of PP with respect to height c" + if len(PP) == 0: + return [] + b = len(PP) + a = len(PP[0]) + return [[c-PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] + + if a*b*c % 2 == 1: + return + + if b % 2 == 1: + for la in possible_middle_row_for_b_odd(a,c): # la is the middle row of SCPP + 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) + print(PP_above,PP_below) + #LIST.append(PP_above+[la]+PP_below) + yield self.element_class(self, PP_above+[la]+PP_below) + #yield 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 + for PP in PPs_with_first_row_la_and_with_k_rows(la,b/2): + PP_below = PP + PP_above = complement(PP_below,c) + #LIST.append(PP_above+PP_below) + print(PP_above,PP_below) + yield self.element_class(self, PP_above+PP_below) + #yield PP_above+PP_below + return + + def cardinality(self): + r=self._box[0] + s=self._box[1] + t=self._box[2] + if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in [1..r/2] for j in [1..s/2] for k in [1..t/2])))^2 +# if r % 2 == 1 and s % 2 == 0 and t % 2 == 0: +# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2] for j in [1..s/2] for k in [1..t/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2+1] for j in [1..s/2] for k in [1..t/2]))) +# if r % 2 == 0 and s % 2 == 1 and t % 2 == 0: +# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2] for k in [1..t/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2+1] for k in [1..t/2]))) +# if r % 2 == 0 and s % 2 == 0 and t % 2 == 1: +# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..s/2] for k in [1..(t-1)/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..s/2] for k in [1..(t-1)/2+1]))) +# if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: +# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2+1] for j in [1..(s-1)/2] for k in [1..t/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2] for j in [1..(s-1)/2+1] for k in [1..t/2]))) +# if r % 2 == 1 and s % 2 == 0 and t % 2 == 1: +# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2+1] for j in [1..s/2] for k in [1..(t-1)/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2] for j in [1..s/2] for k in [1..(t-1)/2+1]))) +# if r % 2 == 0 and s % 2 == 1 and t % 2 == 1: +# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2+1] for k in [1..(t-1)/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2] for k in [1..(t-1)/2+1]))) +# if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: #Class 6 From bbcd9e0fe5af5d5e16e335e03defa31506673ac1 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Mon, 7 Oct 2019 19:14:46 -0500 Subject: [PATCH 26/74] SCPP cardinality and minor cleanup --- src/sage/combinat/plane_partition.py | 35 ++++++++++++---------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 8939c796cdf..7ed8676ceb4 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1909,19 +1909,13 @@ def complement(PP,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) - print(PP_above,PP_below) - #LIST.append(PP_above+[la]+PP_below) yield self.element_class(self, PP_above+[la]+PP_below) - #yield 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 for PP in PPs_with_first_row_la_and_with_k_rows(la,b/2): PP_below = PP PP_above = complement(PP_below,c) - #LIST.append(PP_above+PP_below) - print(PP_above,PP_below) yield self.element_class(self, PP_above+PP_below) - #yield PP_above+PP_below return def cardinality(self): @@ -1929,20 +1923,21 @@ def cardinality(self): s=self._box[1] t=self._box[2] if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in [1..r/2] for j in [1..s/2] for k in [1..t/2])))^2 -# if r % 2 == 1 and s % 2 == 0 and t % 2 == 0: -# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2] for j in [1..s/2] for k in [1..t/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2+1] for j in [1..s/2] for k in [1..t/2]))) -# if r % 2 == 0 and s % 2 == 1 and t % 2 == 0: -# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2] for k in [1..t/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2+1] for k in [1..t/2]))) -# if r % 2 == 0 and s % 2 == 0 and t % 2 == 1: -# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..s/2] for k in [1..(t-1)/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..s/2] for k in [1..(t-1)/2+1]))) -# if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: -# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2+1] for j in [1..(s-1)/2] for k in [1..t/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2] for j in [1..(s-1)/2+1] for k in [1..t/2]))) -# if r % 2 == 1 and s % 2 == 0 and t % 2 == 1: -# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2+1] for j in [1..s/2] for k in [1..(t-1)/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..(r-1)/2] for j in [1..s/2] for k in [1..(t-1)/2+1]))) -# if r % 2 == 0 and s % 2 == 1 and t % 2 == 1: -# return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2+1] for k in [1..(t-1)/2]))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in [1..r/2] for j in [1..(s-1)/2] for k in [1..(t-1)/2+1]))) -# if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) + if r % 2 == 1 and s % 2 == 0 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+t/2)))) + if r % 2 == 0 and s % 2 == 1 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) + if r % 2 == 0 and s % 2 == 0 and t % 2 == 1: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) + if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) + if r % 2 == 1 and s % 2 == 0 and t % 2 == 1: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) + if r % 2 == 0 and s % 2 == 1 and t % 2 == 1: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+(t-1)/2+1)))) + if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: + return 0 #Class 6 From 951a322585643b6d0a30d092ca6cae9f2a7da1ea Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 10 Oct 2019 11:01:33 -0500 Subject: [PATCH 27/74] Large number of changes I did not intermittently commit --- src/sage/combinat/plane_partition.py | 149 +++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 7ed8676ceb4..331908daa09 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -39,7 +39,7 @@ from sage.misc.all import prod from sage.combinat.tableau import Tableau from sage.arith.misc import Sigma -from sage.functions.other import floor, ceil +from sage.functions.other import floor, ceil, binomial @@ -155,7 +155,7 @@ def z_tableau(self): sage: PP.z_tableau() [[4, 3, 3, 1], [2, 1, 1, 0], [1, 1, 0, 0]] """ - Z = [[0 for i in range(self._max_y)] for j in range(self._max_x)] + Z = [[0 for i in range(self._max_x)] for j in range(self._max_y)] for C in self.cells(): Z[C[0]][C[1]] += 1 return Z @@ -532,11 +532,11 @@ def complement(self, tableau_only=False): A = self._max_x B = self._max_y C = self._max_z - T = [[C for i in range(B)] for j in range(A)] - z_tab = self.z_tableau() + T = [[C for i in range(A)] for j in range(B)] + #z_tab = self.z_tableau() for r in range(A): for c in range(B): - T[A-1-r][B-1-c] = C - z_tab[r][c] + T[B-1-c][A-1-r] = C - self[c][r] if tableau_only: return T else: @@ -584,7 +584,7 @@ def is_SPP(self): sage: PP.is_SPP() True sage: PP = PlanePartition([[3,2,1],[2,0,0]]) - sage: PP.is_SPP() + sage: PP.is_SPP()complement False sage: PP = PlanePartition([[3,2,0],[2,0,0]]) sage: PP.is_SPP() @@ -661,7 +661,7 @@ def is_SCPP(self): sage: PP.is_SCPP() True """ - return self.z_tableau() == self.complement(True) + return self.z_tableau() == self.complement(tableau_only=True) def is_TCPP(self): r""" @@ -840,11 +840,11 @@ class PlanePartitions_all(PlanePartitions): def __init__(self): r""" - Initializes the class of all increasing tableaux. + Initializes the class of all plane partitions. .. WARNING:: - Input is not checked; please use :class:`IncreasingTableaux` to + Input is not checked; please use :class:`PlanePartitions` to ensure the options are properly parsed. TESTS:: @@ -1809,7 +1809,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') sage: TestSuite(PP).run() """ # if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): @@ -1919,6 +1919,49 @@ def complement(PP,c): return def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of self complementary plane partitions inside a + `2a \times 2b \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{r}\prod_{j=1}^{b} \frac{i + j + c - 1}{i + j - 1}\right)^2 + + + + The number of self complementary plane partitions inside an + `2a+1 \times 2b \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + + + The number of self complementary plane partitions inside an + `2a+1 \times 2b+1 \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a}\prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right) + + EXAMPLES:: + + sage: P = PlanePartitions((4,4,4), symmetry='SCPP') + sage: P.cardinality() + 400 + + sage: P = PlanePartitions((5,4,4), symmetry='SCPP') + sage: P.cardinality() + 1000 + + sage: P = PlanePartitions((5,5,4), symmetry='SCPP') + sage: P.cardinality() + 2500 + """ r=self._box[0] s=self._box[1] t=self._box[2] @@ -1950,8 +1993,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((4,3,2), symmetry='TCPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='TCPP') sage: P1 is P2 True """ @@ -1961,11 +2004,11 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([3,3,3], symmetry='TCPP') sage: TestSuite(PP).run() """ - if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("box sides cannot all be odd") +# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): +# raise ValueError("box sides cannot all be odd") super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) self._box=box_size @@ -1973,6 +2016,34 @@ def _repr_(self): return "Transpose complement plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_TCPP(): + yield self.element_class(self,) + return + + + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of transpose complement plane partitions inside an + `a \times a \times 2b` box is equal to + + .. MATH:: + + \binom{b+1-1}{a-1}\prod_{1\leq i\leq j a-2} \frac{i + j + 2b - 1}{i + j - 1} + """ + + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a==b and c % 2 == 0: + 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))) + else: + return 0 + #Class 7 class PlanePartitions_SSCPP(PlanePartitions): @@ -1983,8 +2054,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((4,3,2), symmetry='SSCPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='SSCPP') sage: P1 is P2 True """ @@ -1994,7 +2065,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([3,3,3], symmetry='SSCPP') sage: TestSuite(PP).run() """ if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): @@ -2006,6 +2077,22 @@ def _repr_(self): return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_SSCPP(): + yield self.element_class(self,) + return + + def cardinality(self): + r=self._box[0] + s=self._box[1] + t=self._box[2] + if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+r/2) for k in range(1,1+t/2)))) + if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+(r-1)/2) for j in range(1,1+((r-1)/2)+1) for k in range(1,1+t/2)))) + return 0 + #Class 8 class PlanePartitions_CSTCPP(PlanePartitions): @@ -2038,6 +2125,20 @@ def _repr_(self): return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_CSTCPP(): + yield self.element_class(self,) + return + + def cardinality(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a == b and b == c and a % 2 == 0: + return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range(1+(a/2)-1))) + return 0 + #Class 9 @@ -2071,7 +2172,19 @@ def _repr_(self): return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_CSSCPP(): + yield self.element_class(self,) + return + def cardinality(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a == b and b == c and a % 2 == 0: + return Integer(prod( ((factorial(3*i+1)**2/(factorial(a+i)**2) for i in range((a/2)))))) + return 0 From 86f02f986a06e4f99ab5611e956414974d760f78 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 10 Oct 2019 11:13:44 -0500 Subject: [PATCH 28/74] Changed iterator for TSSCPP --- src/sage/combinat/plane_partition.py | 288 ++++++++++++++++++--------- 1 file changed, 199 insertions(+), 89 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 331908daa09..416a263b39b 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1608,7 +1608,7 @@ def __iter__(self): # if j < c-1: # jValue = ppMatrix[i][j+1] # ppMatrix[i][j] = max(iValue,jValue) - yield self.from_antichain() + yield self.from_antichain(acl) def cardinality(self): r""" @@ -2222,8 +2222,8 @@ def _repr_(self): return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - - def __iter__(self): + def to_poset(self): + cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) def componentwise_comparer(thing1,thing2): if len(thing1) == len(thing2): if all(thing1[i] <= thing2[i] for i in range(len(thing1))): @@ -2232,100 +2232,210 @@ def componentwise_comparer(thing1,thing2): a=self._box[0] b=self._box[1] c=self._box[2] - n = a - b = n - c = n + if a != b or b != c or a != c: + return pl = [] - for x in range(0,n/2 - 2 + 1): - for y in range(x, n/2 - 2 + 1): - for z in range(0,n/2 - 2 + 1): - if z <= n/2 - 2 - y: + for x in range(0,a/2 - 2 + 1): + for y in range(x, a/2 - 2 + 1): + for z in range(0,a/2 - 2 + 1): + if z <= a/2 - 2 - y: pl.append((x,y,z)) - pocp = Poset((pl,componentwise_comparer)) - cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) + return Poset((pl,cmp)) + + def from_antichain(self, acl): + #ac format ex: [x,y,z] + a=self._box[0] + b=self._box[1] + c=self._box[2] + n=a + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + width = n/2 - 1 + height = n/2 - 1 + + #generate inner triagle + for i in range(width): + for j in range(height): + if(i <= j): + for ac in acl: + if ac[0] == i and ac[1] == j: + zVal = ac[2] + matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] + if zVal + 1 > matrixVal: + ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 + + #fill back + for i in range(width): + i = width-(i+1) + i = i + n/2 + for j in range(height): + j = height-(j+1) + j = j + n/2 + if (ppMatrix[i][j] == 0): + if i >= j: + iValue = 0 + jValue = 0 + if i < n: + iValue = ppMatrix[i+1][j] + if j < n: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + + + #fill half of triangle symmetrically + for i in range(width): + i = i + n/2 + for j in range(height): + j = j + n/2 + if i >= j: + ppMatrix[j][i] = ppMatrix[i][j] + + #upper left box + for i in range(n/2): + for j in range(n/2): + ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] + + + #fill in lower left cube with values n/2 + for i in range(n/2): + for j in range(n/2): + x = i + y = j + if(ppMatrix[x][y+(n/2)]) == 0: + ppMatrix[x][y+(n/2)] = n/2 + if(ppMatrix[x+(n/2)][y]) == 0: + ppMatrix[x+(n/2)][y] = n/2 + + + #add and subtract values from lower left cube to be rotation of lower right cube + for i in range(n/2): + for j in range(n/2): + x = i+(n/2) + y = j+(n/2) + if ppMatrix[x][y] > 0: + z = ppMatrix[x][y] + for cVal in range(z): + #build onto lower left cube + ppMatrix[x][0+cVal] += 1 + #carve out of lower left cube + ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 + + #fill in upper right cube symmetrically with lower left + for i in range(n/2): + for j in range(n/2): + ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] + return self.element_class(self, ppMatrix) + + + + + + def __iter__(self): +# def componentwise_comparer(thing1,thing2): +# if len(thing1) == len(thing2): +# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): +# return True +# return False +# a=self._box[0] +# b=self._box[1] +# c=self._box[2] +# n = a +# b = n +# c = n + +# pl = [] +# for x in range(0,n/2 - 2 + 1): +# for y in range(x, n/2 - 2 + 1): +# for z in range(0,n/2 - 2 + 1): +# if z <= n/2 - 2 - y: +# pl.append((x,y,z)) + +# pocp = Poset((pl,componentwise_comparer)) +# cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) # pocp = Poset((pl,cmp)) # matrixList = [] #list of all PlaneParitions with parameters(a,b,c) #iterate through each antichain of product of chains poset with paramaters (a,b,c) - for acl in pocp.antichains_iterator(): - #ac format ex: [x,y,z] - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - width = n/2 - 1 - height = n/2 - 1 - - #generate inner triagle - for i in range(width): - for j in range(height): - if(i <= j): - for ac in acl: - if ac[0] == i and ac[1] == j: - zVal = ac[2] - matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] - if zVal + 1 > matrixVal: - ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 - - #fill back - for i in range(width): - i = width-(i+1) - i = i + n/2 - for j in range(height): - j = height-(j+1) - j = j + n/2 - if (ppMatrix[i][j] == 0): - if i >= j: - iValue = 0 - jValue = 0 - if i < n: - iValue = ppMatrix[i+1][j] - if j < n: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - - - #fill half of triangle symmetrically - for i in range(width): - i = i + n/2 - for j in range(height): - j = j + n/2 - if i >= j: - ppMatrix[j][i] = ppMatrix[i][j] + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + return +# #ac format ex: [x,y,z] +# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] +# width = n/2 - 1 +# height = n/2 - 1 + +# #generate inner triagle +# for i in range(width): +# for j in range(height): +# if(i <= j): +# for ac in acl: +# if ac[0] == i and ac[1] == j: +# zVal = ac[2] +# matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] +# if zVal + 1 > matrixVal: +# ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 + +# #fill back +# for i in range(width): +# i = width-(i+1) +# i = i + n/2 +# for j in range(height): +# j = height-(j+1) +# j = j + n/2 +# if (ppMatrix[i][j] == 0): +# if i >= j: +# iValue = 0 +# jValue = 0 +# if i < n: +# iValue = ppMatrix[i+1][j] +# if j < n: +# jValue = ppMatrix[i][j+1] +# ppMatrix[i][j] = max(iValue,jValue) + - #upper left box - for i in range(n/2): - for j in range(n/2): - ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] - - - #fill in lower left cube with values n/2 - for i in range(n/2): - for j in range(n/2): - x = i - y = j - if(ppMatrix[x][y+(n/2)]) == 0: - ppMatrix[x][y+(n/2)] = n/2 - if(ppMatrix[x+(n/2)][y]) == 0: - ppMatrix[x+(n/2)][y] = n/2 - - - #add and subtract values from lower left cube to be rotation of lower right cube - for i in range(n/2): - for j in range(n/2): - x = i+(n/2) - y = j+(n/2) - if ppMatrix[x][y] > 0: - z = ppMatrix[x][y] - for cVal in range(z): - #build onto lower left cube - ppMatrix[x][0+cVal] += 1 - #carve out of lower left cube - ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 - - #fill in upper right cube symmetrically with lower left - for i in range(n/2): - for j in range(n/2): - ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] - yield self.element_class(self, ppMatrix) +# #fill half of triangle symmetrically +# for i in range(width): +# i = i + n/2 +# for j in range(height): +# j = j + n/2 +# if i >= j: +# ppMatrix[j][i] = ppMatrix[i][j] + +# #upper left box +# for i in range(n/2): +# for j in range(n/2): +# ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] + + +# #fill in lower left cube with values n/2 +# for i in range(n/2): +# for j in range(n/2): +# x = i +# y = j +# if(ppMatrix[x][y+(n/2)]) == 0: +# ppMatrix[x][y+(n/2)] = n/2 +# if(ppMatrix[x+(n/2)][y]) == 0: +# ppMatrix[x+(n/2)][y] = n/2 + + +# #add and subtract values from lower left cube to be rotation of lower right cube +# for i in range(n/2): +# for j in range(n/2): +# x = i+(n/2) +# y = j+(n/2) +# if ppMatrix[x][y] > 0: +# z = ppMatrix[x][y] +# for cVal in range(z): +# #build onto lower left cube +# ppMatrix[x][0+cVal] += 1 +# #carve out of lower left cube +# ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 + +# #fill in upper right cube symmetrically with lower left +# for i in range(n/2): +# for j in range(n/2): +# ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] +# yield self.element_class(self, ppMatrix) From 80fcff4cdf054f3478b895828945a4eee3f94505 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Sat, 7 Dec 2019 00:22:34 -0600 Subject: [PATCH 29/74] Made numerous changes --- src/sage/combinat/plane_partition.py | 238 ++++++++++++++++----------- 1 file changed, 138 insertions(+), 100 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 416a263b39b..35f49b4b88e 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -39,7 +39,7 @@ from sage.misc.all import prod from sage.combinat.tableau import Tableau from sage.arith.misc import Sigma -from sage.functions.other import floor, ceil, binomial +from sage.functions.other import floor, ceil, binomial, factorial @@ -53,12 +53,12 @@ def __classcall_private__(cls, PP): EXAMPLES:: sage: p = PlanePartition([[2,1],[1]]) - sage: TestSuite(t).run() + sage: TestSuite(p).run() sage: p.parent() Plane partitions sage: p.category() - Category of elements of plane partitions + Category of elements of Plane partitions sage: type(p) """ @@ -74,7 +74,7 @@ def __init__(self, parent, pp, check=True): TESTS:: sage: a = PlanePartitions()([[2,1],[1]]) - sage: b = PlanePartitions([2,2,2])([[2,1],[1])) + sage: b = PlanePartitions([2,2,2])([[2,1],[1]]) sage: c = PlanePartitions(4)([[2,1],[1]]) Add more tests to show which parent a,b,c receive, check that a==b, and b==c, but a is not b, and b is not c. @@ -82,7 +82,7 @@ def __init__(self, parent, pp, check=True): """ if isinstance(pp, PlanePartition): ClonableList.__init__(self, parent, pp, check=False) - pp = [tuple(_) for _ in pp] + pp = [list(_) for _ in pp] ClonableList.__init__(self, parent, pp, check=check) if self.parent()._box is None: if pp: @@ -155,7 +155,7 @@ def z_tableau(self): sage: PP.z_tableau() [[4, 3, 3, 1], [2, 1, 1, 0], [1, 1, 0, 0]] """ - Z = [[0 for i in range(self._max_x)] for j in range(self._max_y)] + Z = [[0 for i in range(self._max_y)] for j in range(self._max_x)] for C in self.cells(): Z[C[0]][C[1]] += 1 return Z @@ -207,6 +207,18 @@ def cells(self): L.append([r,c,h]) return L + def number_of_boxes(self): + r""" + Return the number of boxes in the plane partition. + + EXAMPLES:: + + sage: PP = PlanePartition([[3,1],[2]]) + sage: PP.number_of_boxes() + 6 + """ + return sum(sum(k for k in row) for row in self) + def _repr_diagram(self, show_box=False, use_unicode=False): r""" Return a string of the 3D diagram of ``self``. @@ -510,14 +522,15 @@ def add_rightside(i, j, k): return TP def complement(self, tableau_only=False): + # Complement needs to be more intelligent about which parent to return r""" Return the complement of ``self``. - If the parent of ``self'' consists only of partitions inside a given + If the parent of ``self`` consists only of partitions inside a given box, then the complement is taken in this box. Otherwise, the complement is taken in the smallest box containing the plane partition. - If ``tableau_only'' is set to ``True'', then only the tableau + If ``tableau_only`` is set to ``True``, then only the tableau consisting of the projection of boxes size onto the xy-plane is returned instead of a PlanePartition object. @@ -532,11 +545,11 @@ def complement(self, tableau_only=False): A = self._max_x B = self._max_y C = self._max_z - T = [[C for i in range(A)] for j in range(B)] - #z_tab = self.z_tableau() + T = [[C for i in range(B)] for j in range(A)] + z_tab = self.z_tableau() for r in range(A): for c in range(B): - T[B-1-c][A-1-r] = C - self[c][r] + T[A-1-r][B-1-c] = C - z_tab[r][c] if tableau_only: return T else: @@ -546,7 +559,7 @@ def transpose(self, tableau_only=False): r""" Return the transpose of ``self``. - If ``tableau_only'' is set to ``True'', then only the tableau + If ``tableau_only`` is set to ``True``, then only the tableau consisting of the projection of boxes size onto the xy-plane is returned instead of a PlanePartition object. @@ -584,7 +597,7 @@ def is_SPP(self): sage: PP.is_SPP() True sage: PP = PlanePartition([[3,2,1],[2,0,0]]) - sage: PP.is_SPP()complement + sage: PP.is_SPP() False sage: PP = PlanePartition([[3,2,0],[2,0,0]]) sage: PP.is_SPP() @@ -781,7 +794,7 @@ def __classcall_private__(cls, *args, **kwds): sage: PlanePartitions(3) 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 + Totally symmetric self-complementary plane partitions inside a 4 x 4 x 4 box """ symmetry = kwds.get('symmetry', None) if not args: @@ -821,7 +834,25 @@ def __classcall_private__(cls, *args, **kwds): Element = PlanePartition + def __contains__(self, pp): + """ + Check to see that ``self`` is a valid plane partition. + .. TODO: + + Figure out how redundant this is, given that the check function + exists for the factor class. Maybe only need __contains__ + on the fixed size and symmetry classes? + """ + for row in pp: + if not all(c >= 0 for c in row): + return False + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + return False + for row, next in zip(pp, pp[1:]): + if not all(row[c] >= next[c] for c in range(len(next))): + return False + return True @@ -849,8 +880,8 @@ def __init__(self): TESTS:: - sage: from sage.combinat.plane_partition import PlanePartition_all - sage: P = PlanePartition_all() + sage: from sage.combinat.plane_partition import PlanePartitions_all + sage: P = PlanePartitions_all() sage: TestSuite(P).run() # long time """ self._box = None @@ -867,25 +898,7 @@ def __repr__(self): """ return "Plane partitions" - def __contains__(self, pp): - """ - Check to see that ``self`` is a valid plane partition. - .. TODO: - - Figure out how redundant this is, given that the check function - exists for the factor class. Maybe only need __contains__ - on the fixed size and symmetry classes? - """ - for row in pp: - if not all(c >= 0 for c in row): - return False - if not all(row[i] >= row[i+1] for i in range(len(row)-1)): - return False - for row, next in zip(pp, pp[1:]): - if not all(row[c] >= next[c] for c in range(len(next))): - return False - return True class PlanePartitions_box(PlanePartitions): @@ -944,7 +957,7 @@ def to_poset(self): def from_order_ideal(self, I): r""" Return the plane partition corresponding to an order ideal in the - poset given in (LINK) to_poset(). + poset given in :meth:`to_poset`. Note: input may not be checked ? Optional check parameter if too much overhead? """ @@ -953,14 +966,14 @@ def from_order_ideal(self, I): def from_antichain(self, A): r""" Return the plane partition corresponding to an antichain in the poset - given in (LINK) to_poset(). + given in :meth:`to_poset`. Note: input may not be checked? Optional parameter if too much overhead? """ a = self._box[0] b = self._box[1] c = self._box[2] - ppMatrix = [[0] * (a) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + ppMatrix = [[0] * (b) for i in range(a)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] #ac format ex: [x,y,z] #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) @@ -968,7 +981,7 @@ def from_antichain(self, A): x = ac[0] y = ac[1] z = ac[2] - ppMatrix[y][x] = (z+1) + ppMatrix[x][y] = (z+1) #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format if A != []: @@ -976,14 +989,14 @@ def from_antichain(self, A): i = a-(i+1) for j in range(b): j = b-(j+1) - if (ppMatrix[j][i] == 0): + if (ppMatrix[i][j] == 0): iValue = 0 jValue = 0 if i < a-1: - iValue = ppMatrix[j][i+1] + iValue = ppMatrix[i+1][j] if j < b-1: - jValue = ppMatrix[j+1][i] - ppMatrix[j][i] = max(iValue,jValue) + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) return self.element_class(self, ppMatrix) @@ -994,9 +1007,7 @@ def __iter__(self): EXAMPLES:: sage: list(PlanePartitions((1,2,1))) - [Plane partition [[0, 0]], - Plane partition [[1, 0]], - Plane partition [[1, 1]]] + [Plane partition [[0, 0]], Plane partition [[1, 1]], Plane partition [[1, 0]]] """ # A = self._box[0] # B = self._box[1] @@ -1159,6 +1170,7 @@ def __init__(self, n): """ super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) self._n = n + self._box = (0,0,0) def _repr_(self): """ @@ -1169,6 +1181,9 @@ def _repr_(self): """ return "Plane partitions of size {}".format(self._n) + def __contains__(self, x): + return PlanePartitions.__contains__(self, x) and x.number_of_boxes() == self._n + def __iter__(self): from sage.combinat.partition import Partitions def PP_first_row_iter(n, la): @@ -1217,7 +1232,8 @@ def P_in_shape_iter(n, la): for m in range(n,0,-1): for la in Partitions(m): for a in PP_first_row_iter(n,la): - yield PlanePartition(a) +# yield PlanePartition(a) + yield self.element_class(self, a, check=False) def cardinality(self): r""" @@ -1237,7 +1253,7 @@ def cardinality(self): for i in range(1,1+self._n): nextPPn = sum(PPn[i-k]*Sigma()(k,2) for k in range(1,i+1))/i PPn.append(nextPPn) - return(PPn[-1]) + return(Integer(PPn[-1])) #Symmetry classes are enumerated and labelled in order as in Proofs and #Confirmations/Stanley (with all plane partitions being the first class) @@ -1249,6 +1265,8 @@ def cardinality(self): class PlanePartitions_SPP(PlanePartitions): +#How to handle when a!=b ? + @staticmethod def __classcall_private__(cls, box_size): """ @@ -1256,8 +1274,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2), symmetry='SPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='SPP') + sage: P1 = PlanePartitions((3,3,2), symmetry='SPP') + sage: P2 = PlanePartitions([3,3,2], symmetry='SPP') sage: P1 is P2 True """ @@ -1267,7 +1285,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry='SPP') + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') sage: TestSuite(PP).run() """ super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) @@ -1313,35 +1331,36 @@ def from_antichain(self, A): Note: input may not be checked? Optional parameter if too much overhead? """ + from copy import deepcopy #Initialize an empty plane partition a=self._box[0] b=self._box[1] c=self._box[2] - ppMatrix = [[0] * (a) for i in range(b)] + ppMatrix = [[0] * (b) for i in range(a)] #Antichain indicates where the 'corners' will be in the #plane partition for ac in A: x=ac[0] y=ac[1] z=ac[2] - ppMatrix[y][x] = (z+1) + ppMatrix[x][y] = (z+1) #Fill out the rest of the plane partition using symmetry and the #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) if A!= []: - for j in range(b): - j = b-(j+1) - for i in range(a): - i = a-(i+1) - if (ppMatrix[j][i] == 0) and j>=i: + for i in range(a): + i = a-(i+1) + for j in range(b): + j = b-(j+1) + if (ppMatrix[i][j] == 0) and i>=j: iValue = 0 jValue = 0 if i < a-1: - iValue = ppMatrix[j][i+1] + iValue = ppMatrix[i+1][j] if j < b-1: - jValue = ppMatrix[j+1][i] - ppMatrix[j][i] = max(iValue,jValue) - elif i>j: - ppMatrix[j][i] = ppMatrix[i][j] + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + elif j>i: + ppMatrix[i][j] = ppMatrix[j][i] return self.element_class(self, ppMatrix) def __iter__(self): @@ -1452,7 +1471,7 @@ def cardinality(self): C = self._box[2] leftProduct = (prod( (2*i + C - 1) / (2*i - 1) for i in range(1,A+1))) rightProduct = (prod( (i + j + C - 1) / (i + j - 1) for j in range(1, A+1) for i in range(1, j) )) - return leftProduct * rightProduct + return Integer(leftProduct * rightProduct) def random_element(self): r""" @@ -1478,6 +1497,8 @@ def random_element(self): class PlanePartitions_CSPP(PlanePartitions): +#For some reason works if not(a == b == c) + @staticmethod def __classcall_private__(cls, box_size): """ @@ -1523,7 +1544,10 @@ def to_poset(self): pl.append((x,y,z)) return Poset((pl, cmp2)) - def from_antichain(self): + def from_antichain(self, acl): + a=self._box[0] + b=self._box[1] + c=self._box[2] ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] #ac format ex: [x,y,z] @@ -1557,7 +1581,7 @@ def from_antichain(self): def from_order_ideal(self, I): r""" Return the plane partition corresponding to an order ideal in the - poset given in (LINK) to_poset(). + poset given in :meth:`to_poset`. Note: input may not be checked ? Optional check parameter if too much overhead? """ @@ -1633,7 +1657,7 @@ def cardinality(self): C = self._box[2] 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 numerator/denominator + return Integer(numerator/denominator) #Class 4 @@ -1641,6 +1665,8 @@ def cardinality(self): class PlanePartitions_TSPP(PlanePartitions): +#Make sure inputs checked, code doesn't have a,b,c treated properly + @staticmethod def __classcall_private__(cls, box_size): """ @@ -1666,10 +1692,13 @@ def __init__(self, box_size): self._box=box_size def _repr_(self): - return "Transpose symmetric plane partitions inside a {} x {} x {} box".format( + return "Totally symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) def to_poset(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) pl = [] for x in range(0,a): @@ -1678,18 +1707,24 @@ def to_poset(self): pl.append((x,y,z)) return Poset((pl,cmp)) - def from_antichain(self): - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - ppMatrix[y][z] = (x+1) #x,y,z - ppMatrix[z][x] = (y+1) #y,z,x - ppMatrix[x][y] = (z+1) #z,x,y + def from_antichain(self, acl): + a=self._box[0] + b=self._box[1] + c=self._box[2] + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + + + ppMatrix[y][z] = (x+1) #x,y,z + ppMatrix[z][x] = (y+1) #y,z,x + ppMatrix[x][y] = (z+1) #z,x,y - ppMatrix[z][y] = (x+1) #x,z,y - ppMatrix[x][z] = (y+1) #y,x,z - ppMatrix[y][x] = (z+1) #z,y,x + ppMatrix[z][y] = (x+1) #x,z,y + ppMatrix[x][z] = (y+1) #y,x,z + ppMatrix[y][x] = (z+1) #z,y,x #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format @@ -1768,7 +1803,7 @@ def cardinality(self): r""" Return the cardinality of ``self``. - The number of transpose symmetric plane partitions inside an + The number of totally symmetric plane partitions inside an `r \times r \times r` box is equal to .. MATH:: @@ -1784,7 +1819,7 @@ def cardinality(self): A = self._box[0] B = self._box[1] C = self._box[2] - return (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) / (i + 2*j - 2) for j in range(1,A+1) for i in range(1,j+1) )) @@ -1980,7 +2015,7 @@ def cardinality(self): if r % 2 == 0 and s % 2 == 1 and t % 2 == 1: return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+(t-1)/2+1)))) if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: - return 0 + return Integer(0) #Class 6 @@ -2019,7 +2054,7 @@ def _repr_(self): def __iter__(self): for p in PlanePartitions(self._box): if p.is_TCPP(): - yield self.element_class(self,) + yield self.element_class(self,p) return @@ -2042,7 +2077,7 @@ def cardinality(self): if a==b and c % 2 == 0: 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))) else: - return 0 + return Integer(0) #Class 7 @@ -2054,8 +2089,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2), symmetry='SSCPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='SSCPP') + sage: P1 = PlanePartitions((4,4,2), symmetry='SSCPP') + sage: P2 = PlanePartitions([4,4,2], symmetry='SSCPP') sage: P1 is P2 True """ @@ -2065,9 +2100,12 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry='SSCPP') + sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') sage: TestSuite(PP).run() """ + +#Think about how to check a=b and not all a,b,c odd + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): raise ValueError("box sides cannot all be odd") super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) @@ -2080,7 +2118,7 @@ def _repr_(self): def __iter__(self): for p in PlanePartitions(self._box): if p.is_SSCPP(): - yield self.element_class(self,) + yield self.element_class(self,p) return def cardinality(self): @@ -2091,7 +2129,7 @@ def cardinality(self): return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+r/2) for k in range(1,1+t/2)))) if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+(r-1)/2) for j in range(1,1+((r-1)/2)+1) for k in range(1,1+t/2)))) - return 0 + return Integer(0) #Class 8 @@ -2104,8 +2142,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((3,3,3), symmetry='CSTCPP') + sage: P2 = PlanePartitions([3,3,3], symmetry='CSTCPP') sage: P1 is P2 True """ @@ -2115,7 +2153,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([3,3,3], symmetry='CSTCPP') sage: TestSuite(PP).run() """ super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) @@ -2128,7 +2166,7 @@ def _repr_(self): def __iter__(self): for p in PlanePartitions(self._box): if p.is_CSTCPP(): - yield self.element_class(self,) + yield self.element_class(self,p) return def cardinality(self): @@ -2137,7 +2175,7 @@ def cardinality(self): c=self._box[2] if a == b and b == c and a % 2 == 0: return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range(1+(a/2)-1))) - return 0 + return Integer(0) #Class 9 @@ -2151,8 +2189,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((3,3,3), symmetry='CSSCPP') + sage: P2 = PlanePartitions([3,3,3], symmetry='CSSCPP') sage: P1 is P2 True """ @@ -2162,7 +2200,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([3,3,3], symmetry='CSSCPP') sage: TestSuite(PP).run() """ super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) @@ -2184,7 +2222,7 @@ def cardinality(self): c=self._box[2] if a == b and b == c and a % 2 == 0: return Integer(prod( ((factorial(3*i+1)**2/(factorial(a+i)**2) for i in range((a/2)))))) - return 0 + return Integer(0) @@ -2199,8 +2237,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) + sage: P1 = PlanePartitions((4,4,4), symmetry='TSSCPP') + sage: P2 = PlanePartitions([4,4,4], symmetry='TSSCPP') sage: P1 is P2 True """ @@ -2210,7 +2248,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry=TSPP) + sage: PP = PlanePartitions([4,4,4], symmetry='TSSCPP') sage: TestSuite(PP).run() """ if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): From 1eeeff5b2945f163a42fae3cad20d27c7f0b07cf Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 13 Feb 2020 19:50:26 -0600 Subject: [PATCH 30/74] Added code to remove trailing zeros and empty parts. Breaks many testssr --- src/sage/combinat/plane_partition.py | 399 +++++++++------------------ 1 file changed, 133 insertions(+), 266 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 35f49b4b88e..c2b19c81699 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -82,19 +82,27 @@ def __init__(self, parent, pp, check=True): """ if isinstance(pp, PlanePartition): ClonableList.__init__(self, parent, pp, check=False) - pp = [list(_) for _ in pp] - ClonableList.__init__(self, parent, pp, check=check) - if self.parent()._box is None: + else: + pp = [list(_) for _ in pp] if pp: - self._max_x = len(pp) - self._max_y = len(pp[0]) - self._max_z = pp[0][0] + 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) + + ClonableList.__init__(self, parent, pp, check=check) + if self.parent()._box is None: + if pp: + self._max_x = len(pp) + self._max_y = len(pp[0]) + self._max_z = pp[0][0] + else: + self._max_x = 0 + self._max_y = 0 + self._max_z = 0 else: - self._max_x = 0 - self._max_y = 0 - self._max_z = 0 - else: - (self._max_x, self._max_y, self._max_z) = self.parent()._box + (self._max_x, self._max_y, self._max_z) = self.parent()._box def check(self): """ @@ -762,9 +770,100 @@ def is_TSSCPP(self): sage: PP.is_TSSCPP() True """ - return self.is_TSPP() and self.is_SCPP() + return self.is_TSPP() and self.is_SCPP() + + def to_order_ideal(self): + """ + Return the order ideal corresponding to ``self``. + + TODO: As many families of symmetric plane partitions are in bijection + with order ideals in an associated poset, this function could + feasibly have options to send symmetric plane partitions + to the associated order ideal in that poset, instead. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] + sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] + """ + (a, b, c) = (self._max_x, self._max_y, self._max_z) + Q = posets.ProductOfChains([a,b,c]) + count = 0 + generate = [] + for i in range(len(self)): + for j in range(len(self[i])): + if (self[i][j] > 0): + generate.append((i,j,self[i][j]-1)) + count += 1 + oi = Q.order_ideal(generate) + return oi + + def maximal_boxes(self): + """ + Return the coordinates of the maximal boxes of ``self``. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes() + [[0, 2, 0], [1, 1, 1], [0, 0, 2], [2, 0, 1]] + sage: PlanePartition([[2,1],[1],[1]]).maximal_boxes() + [[0, 1, 0], [0, 0, 1], [2, 0, 0]] + """ + (a, b, c) = (self._max_x, self._max_y, self._max_z) + Q = posets.ProductOfChains([a,b,c]) + count = 0 + generate = [] + for i in range(len(self)): + for j in range(len(self[i])): + if (self[i][j] > 0): + generate.append((i,j,self[i][j]-1)) + count+=1 + oi = Q.order_ideal_generators(generate) + return [list(oi_elem) for oi_elem in oi] + def cyclically_rotate(self): + """ + Return the cyclic rotation of ``self``. + TODO: Ensure that parent is preserved under cyclic rotation. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).cyclically_rotate() + Plane partition [[3, 3, 1], [2, 2, 0], [1, 0, 0]] + sage: PP = PlanePartition([[4,1],[1],[1]]) + sage: PP.cyclically_rotate() + Plane partition [[3, 1, 1, 1], [1, 0, 0, 0]] + sage: PP == PP.cyclically_rotate().cyclically_rotate().cyclically_rotate() + True + """ + (a, b, c) = (self._max_x, self._max_y, self._max_z) + new_antichain = [] + for elem in self.maximal_boxes(): + new = (elem[1], elem[2], elem[0]) + new_antichain.append(new) + ppMatrix = [[0] * (c) for i in range(b)] + for box in new_antichain: + y = box[0] + z = box[1] + x = box[2] + ppMatrix[y][z] = (x+1) + if new_antichain != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + return PlanePartition(ppMatrix) class PlanePartitions(UniqueRepresentation, Parent): r""" @@ -942,7 +1041,9 @@ def __repr__(self): Plane partitions inside a 4 x 3 x 2 box """ return "Plane partitions inside a %s x %s x %s box" % (self._box[0], self._box[1], self._box[2]) -# return "Plane partitions inside a box" + + def __contains__(self, x): + return PlanePartitions.__contains__(self, x) and len(x) <= self._box[0] and len(x[0]) <= self._box[1] and x[0][0] <= self._box[2] def to_poset(self): r""" @@ -1001,7 +1102,7 @@ def from_antichain(self, A): def __iter__(self): - """ + r""" Iterate over ``self``. EXAMPLES:: @@ -1009,71 +1110,15 @@ def __iter__(self): sage: list(PlanePartitions((1,2,1))) [Plane partition [[0, 0]], Plane partition [[1, 1]], Plane partition [[1, 0]]] """ -# A = self._box[0] -# B = self._box[1] -# C = self._box[2] -# from sage.combinat.tableau import SemistandardTableaux -# for T in SemistandardTableaux([B for i in range(A)], max_entry=C+A): -# PP = [[0 for i in range(B)] for j in range(A)] -# for r in range(A): -# for c in range(B): -# PP[A-1-r][B-1-c] = T[r][c] - r - 1 -# yield self.element_class(self, PP, check=False) -# def componentwise_comparer(thing1,thing2): -# if len(thing1) == len(thing2): -# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): -# return True -# return False -# def product_of_chains_poset(list_of_chain_lengths): -# elem = cartesian_product([range(chain_length) for chain_length in list_of_chain_lengths]) -# return Poset((elem, componentwise_comparer)) - a = self._box[0] b = self._box[1] c = self._box[2] - -# pocp = product_of_chains_poset([a,b,c]) pocp = posets.ProductOfChains([a,b,c]) - matrixList = [] #list of all PlanePartitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with parameters (a,b,c) for acl in self.to_poset().antichains_iterator(): -# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - -# #ac format ex: [x,y,z] -# #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) -# for ac in acl: -# x = ac[0] -# y = ac[1] -# z = ac[2] -# ppMatrix[y][z] = (x+1) - -# #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format -# if acl != []: -# for i in range(b): -# i = b-(i+1) -# for j in range(c): -# j = c-(j+1) -# if (ppMatrix[i][j] == 0): -# iValue = 0 -# jValue = 0 -# if i < b-1: -# iValue = ppMatrix[i+1][j] -# if j < c-1: -# jValue = ppMatrix[i][j+1] -# ppMatrix[i][j] = max(iValue,jValue) -# yield self.element_class(self, ppMatrix) yield self.from_antichain(acl) -# matrixList.append(ppMatrix) #add PlanePartition to list of plane partitions - -# matrixList.sort() -# current = 0 -# while current < len(matrixList): -# yield self.element_class(self, matrixList[current]) -# current += 1 - def cardinality(self): r""" @@ -1129,19 +1174,6 @@ def random_element(self): sage: P.random_element() Plane partition [[4, 3, 3], [4, 0, 0], [2, 0, 0], [0, 0, 0]] """ -# def leq(thing1, thing2): -# return all(thing1[i] <= thing2[i] for i in range(len(thing1))) -# elem = [(i,j,k) for i in range(self._box[0]) for j in range(self._box[1]) -# for k in range(self._box[2])] -# myposet = Poset((elem, leq)) -# a = self._box[0] -# b = self._box[1] -# c = self._box[2] -# P = posets.ProductOfChains([a,b,c]) -# I = P.random_order_ideal() -# Z = [[0 for i in range(b)] for j in range(a)] -# for C in I: -# Z[C[0]][C[1]] += 1 Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) @@ -1170,7 +1202,8 @@ def __init__(self, n): """ super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) self._n = n - self._box = (0,0,0) +# self._box = (0,0,0) + self._box = None def _repr_(self): """ @@ -1185,6 +1218,14 @@ def __contains__(self, x): return PlanePartitions.__contains__(self, x) and x.number_of_boxes() == self._n def __iter__(self): + r""" + An iterator to generate all plane partitions of a fixed size. + + EXAMPLES:: + + sage: list(PlanePartitions(2)) + [Plane partition [[2]], Plane partition [[1, 1]], Plane partition [[1], [1]]] + """ from sage.combinat.partition import Partitions def PP_first_row_iter(n, la): m = n-sum(la) @@ -1232,7 +1273,6 @@ def P_in_shape_iter(n, la): for m in range(n,0,-1): for la in Partitions(m): for a in PP_first_row_iter(n,la): -# yield PlanePartition(a) yield self.element_class(self, a, check=False) def cardinality(self): @@ -1241,7 +1281,7 @@ def cardinality(self): Calculated using the recurrence relation - ..MATH: + .. MATH: PL(n) = \sum_{k=1}^n PL(n-k)\sigma_2(k) @@ -1318,7 +1358,7 @@ def to_poset(self): def from_order_ideal(self, I): r""" Return the plane partition corresponding to an order ideal in the - poset given in (LINK) to_poset(). + poset given in :meth:`to_poset()`. Note: input may not be checked ? Optional check parameter if too much overhead? """ @@ -1327,11 +1367,10 @@ def from_order_ideal(self, I): def from_antichain(self, A): r""" Return the plane partition corresponding to an antichain in the poset - given in (LINK) to_poset(). + given in :meth:`to_poset()`. Note: input may not be checked? Optional parameter if too much overhead? """ - from copy import deepcopy #Initialize an empty plane partition a=self._box[0] b=self._box[1] @@ -1364,90 +1403,9 @@ def from_antichain(self, A): return self.element_class(self, ppMatrix) def __iter__(self): - #Construct poset whose order ideals are naturally in bijection - #with symmetric plane partitions -# cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) -# a=self._box[0] -# b=self._box[1] -# c=self._box[2] -# pl = [] -# for x in range(0,a): -# for y in range(0,x+1): -# for z in range(0,c): -# pl.append((x,y,z)) -# pocp = Poset((pl,cmp)) - #Iterate over antichains in this poset for acl in self.to_poset().antichains_iterator(): -# #Initialize an empty plane partition -# ppMatrix = [[0] * (a) for i in range(b)] -# #Antichain indicates where the 'corners' will be in the -# #plane partition -# for ac in acl: -# x=ac[0] -# y=ac[1] -# z=ac[2] -# ppMatrix[x][y] = (z+1) -# #Fill out the rest of the plane partition using symmetry and the -# #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) -# if acl!= []: -# for i in range(a): -# i = a-(i+1) -# for j in range(b): -# j = b-(j+1) -# if (ppMatrix[i][j] == 0) and i>=j: -# iValue = 0 -# jValue = 0 -# if i < a-1: -# iValue = ppMatrix[i+1][j] -# if j < b-1: -# jValue = ppMatrix[i][j+1] -# ppMatrix[i][j] = max(iValue,jValue) -# elif j>i: -# ppMatrix[i][j] = ppMatrix[j][i] yield self.from_antichain(acl) - - -# cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) -# a=self._box[0] -# b=self._box[1] -# c=self._box[2] -# pl = [] -# for x in range(0,a): -# for y in range(0, b): -# for z in range(0,c): -# if z <= y: -# pl.append((x,y,z)) -# pocp = Poset((pl,cmp)) -# #iterate through each antichain of product of chains poset with paramaters (a,b,c) -# for acl in pocp.antichains_iterator(): -# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] -# #ac format ex: [x,y,z] -# #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) -# for ac in acl: -# x = ac[0] -# y = ac[1] -# z = ac[2] -# ppMatrix[y][z] = (x+1) - -# #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format -# if acl != []: -# for i in range(b): -# i = b-(i+1) -# for j in range(c): -# j = c-(j+1) -# if (ppMatrix[i][j] == 0) and i>=j: -# iValue = 0 -# jValue = 0 -# if i < b-1: -# iValue = ppMatrix[i+1][j] -# if j < c-1: -# jValue = ppMatrix[i][j+1] -# ppMatrix[i][j] = max(iValue,jValue) -# elif j>i: -# ppMatrix[i][j] = ppMatrix[j][i] -# yield self.element_class(self, ppMatrix) - def cardinality(self): r""" Return the cardinality of ``self``. @@ -1588,50 +1546,7 @@ def from_order_ideal(self, I): return self.from_antichain(self.to_poset().order_ideal_generators(I)) def __iter__(self): -# a=self._box[0] -# b=self._box[1] -# c=self._box[2] -# cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) -# cmp2 = lambda x,y : cmp(x,y) or cmp(x,(y[2],y[0],y[1])) or cmp(x,(y[1],y[2],y[0])) - -# pl = [] -# for x in range(0,a): -# for y in range(0, b): -# for z in range(x,c): -# if y <= z and (x != z or y == x): -# pl.append((x,y,z)) -# pocp = Poset((pl, cmp2)) -# matrixList = [] #list of all PlaneParitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with paramaters (a,b,c) for acl in self.to_poset().antichains_iterator(): -# ppMatrix = [[0] * (c) for i in range(b)] -# #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] -# #ac format ex: [x,y,z] -# for ac in acl: -# x = ac[0] -# y = ac[1] -# z = ac[2] -# ppMatrix[y][z] = (x+1) -# ppMatrix[z][x] = (y+1) -# ppMatrix[x][y] = (z+1) - - -# #for each value in current antichain, fill in the rest of the -# #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is -# #now in plane partition format -# if acl != []: -# for i in range(b): -# i = b-(i+1) -# for j in range(c): -# j = c-(j+1) -# if (ppMatrix[i][j] == 0): -# iValue = 0 -# jValue = 0 -# if i < b-1: -# iValue = ppMatrix[i+1][j] -# if j < c-1: -# jValue = ppMatrix[i][j+1] -# ppMatrix[i][j] = max(iValue,jValue) yield self.from_antichain(acl) def cardinality(self): @@ -1643,8 +1558,8 @@ def cardinality(self): .. MATH:: - \prod_{i=1}^{r} \frac{3*i - 1}{3*i - 2} * - \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{2*i+j-1} + \left(\prod_{i=1}^{r} \frac{3i - 1}{3i - 2}\right) + \left(\prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{2i+j-1}\right) EXAMPLES:: @@ -1749,54 +1664,6 @@ def random_element(self): def __iter__(self): for A in self.to_poset().antichains_iterator(): yield self.from_antichain(A) -# cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) -# pl = [] -# for x in range(0,a): -# for y in range(x, b): -# for z in range(y,c): -# pl.append((x,y,z)) - -# myposet = Poset((pl,cmp)) - -# R = myposet.random_order_ideal() -# acl = R - -# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - -# #ac format ex: [x,y,z] -# for ac in acl: -# x = ac[0] -# y = ac[1] -# z = ac[2] -# ppMatrix[y][z] = (x+1) #x,y,z -# ppMatrix[z][x] = (y+1) #y,z,x -# ppMatrix[x][y] = (z+1) #z,x,y - -# ppMatrix[z][y] = (x+1) #x,z,y -# ppMatrix[x][z] = (y+1) #y,x,z -# ppMatrix[y][x] = (z+1) #z,y,x - - -# #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format -# if acl != []: -# for i in range(b): -# i = b-(i+1) -# for j in range(c): -# j = c-(j+1) -# if (ppMatrix[i][j] == 0): -# iValue = 0 -# jValue = 0 -# if i < b-1: -# iValue = ppMatrix[i+1][j] -# if j < c-1: -# jValue = ppMatrix[i][j+1] -# ppMatrix[i][j] = max(iValue,jValue) - -# return PlanePartition(ppMatrix) - - - - def cardinality(self): @@ -1808,7 +1675,7 @@ def cardinality(self): .. MATH:: - \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{i+2*j-2} + \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{i+2j-2} EXAMPLES:: @@ -1967,7 +1834,7 @@ def cardinality(self): The number of self complementary plane partitions inside an - `2a+1 \times 2b \times 2c` box is equal to + `(2a+1) \times 2b \times 2c` box is equal to .. MATH:: @@ -1976,7 +1843,7 @@ def cardinality(self): The number of self complementary plane partitions inside an - `2a+1 \times 2b+1 \times 2c` box is equal to + `(2a+1) \times (2b+1) \times 2c` box is equal to .. MATH:: From 948d2d22145842999e9fda53e9081a74462a5e55 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 1 Apr 2020 00:12:50 -0500 Subject: [PATCH 31/74] Continued to make changes related to fixing transpose method and removing trailing zeros and empty rows --- src/sage/combinat/plane_partition.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index c2b19c81699..aa6bc2e2875 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -546,9 +546,9 @@ def complement(self, tableau_only=False): sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.complement() - Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] + Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1,]] sage: PP.complement(True) - [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] + [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1]] """ A = self._max_x B = self._max_y @@ -575,9 +575,9 @@ def transpose(self, tableau_only=False): sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.transpose() - Plane partition [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] + Plane partition [[4, 2, 1], [3, 1, 1], [3, 1], [1]] sage: PP.transpose(True) - [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] + [[4, 2, 1], [3, 1, 1], [3, 1], [1]] """ T = [[0 for i in range(self._max_x)] for j in range(self._max_y)] z_tab = self.z_tableau() @@ -586,6 +586,8 @@ def transpose(self, tableau_only=False): T[c][r] = z_tab[r][c] if tableau_only: return T + elif self.box_size[0] != self.box_size[1]: + raise ValueError("Tranpose only supports parents with symmetric dimensions") else: return type(self)(self.parent(), T, check=False) @@ -832,10 +834,10 @@ def cyclically_rotate(self): EXAMPLES:: sage: PlanePartition([[3,2,1],[2,2],[2]]).cyclically_rotate() - Plane partition [[3, 3, 1], [2, 2, 0], [1, 0, 0]] + Plane partition [[3, 3, 1], [2, 2], [1]] sage: PP = PlanePartition([[4,1],[1],[1]]) sage: PP.cyclically_rotate() - Plane partition [[3, 1, 1, 1], [1, 0, 0, 0]] + Plane partition [[3, 1, 1, 1], [1]] sage: PP == PP.cyclically_rotate().cyclically_rotate().cyclically_rotate() True """ @@ -1043,6 +1045,8 @@ def __repr__(self): return "Plane partitions inside a %s x %s x %s box" % (self._box[0], self._box[1], self._box[2]) def __contains__(self, x): + if len(x) == 0: + return True return PlanePartitions.__contains__(self, x) and len(x) <= self._box[0] and len(x[0]) <= self._box[1] and x[0][0] <= self._box[2] def to_poset(self): @@ -1108,7 +1112,7 @@ def __iter__(self): EXAMPLES:: sage: list(PlanePartitions((1,2,1))) - [Plane partition [[0, 0]], Plane partition [[1, 1]], Plane partition [[1, 0]]] + [Plane partition [], Plane partition [[1, 1]], Plane partition [[1]]] """ a = self._box[0] b = self._box[1] @@ -1172,7 +1176,7 @@ def random_element(self): sage: P = PlanePartitions((4,3,5)) sage: P.random_element() - Plane partition [[4, 3, 3], [4, 0, 0], [2, 0, 0], [0, 0, 0]] + Plane partition [[4, 3, 3], [4], [2]] """ Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) @@ -1446,7 +1450,7 @@ def random_element(self): sage: P = PlanePartitions((4,3,5)) sage: P.random_element() - Plane partition [[4, 3, 3], [4, 0, 0], [2, 0, 0], [0, 0, 0]] + Plane partition [[4, 3, 3], [4], [2]] """ Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) From 87b4acb75146a415078c4f9adaf0d055871c409c Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 28 May 2020 21:40:48 -0500 Subject: [PATCH 32/74] Batch of small fixes before tackling tranpose --- src/sage/combinat/plane_partition.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index aa6bc2e2875..8ac335fda25 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -540,15 +540,16 @@ def complement(self, tableau_only=False): If ``tableau_only`` is set to ``True``, then only the tableau consisting of the projection of boxes size onto the xy-plane - is returned instead of a PlanePartition object. + is returned instead of a PlanePartition object. This output will + not have empty trailing rows or trailing zeros removed. EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.complement() - Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1,]] + Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1]] sage: PP.complement(True) - [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1]] + [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] """ A = self._max_x B = self._max_y @@ -569,7 +570,8 @@ def transpose(self, tableau_only=False): If ``tableau_only`` is set to ``True``, then only the tableau consisting of the projection of boxes size onto the xy-plane - is returned instead of a PlanePartition object. + is returned instead of a PlanePartition object. This will + not necessarily have trailing rows or trailing zeros removed. EXAMPLES:: @@ -577,7 +579,7 @@ def transpose(self, tableau_only=False): sage: PP.transpose() Plane partition [[4, 2, 1], [3, 1, 1], [3, 1], [1]] sage: PP.transpose(True) - [[4, 2, 1], [3, 1, 1], [3, 1], [1]] + [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] """ T = [[0 for i in range(self._max_x)] for j in range(self._max_y)] z_tab = self.z_tableau() @@ -586,7 +588,7 @@ def transpose(self, tableau_only=False): T[c][r] = z_tab[r][c] if tableau_only: return T - elif self.box_size[0] != self.box_size[1]: + elif self._max_x != self._max_y: raise ValueError("Tranpose only supports parents with symmetric dimensions") else: return type(self)(self.parent(), T, check=False) From 0cb3123df44de583ab5f7cbb23d87df4f6f5e713 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Sat, 30 May 2020 13:25:45 -0500 Subject: [PATCH 33/74] Hopefully transpose correctly changes parent of output. Indentation fix in PlanePartition init --- src/sage/combinat/plane_partition.py | 78 ++++++++++++++++++---------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 8ac335fda25..03ea99376f8 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -92,17 +92,17 @@ def __init__(self, parent, pp, check=True): pp.pop(i) ClonableList.__init__(self, parent, pp, check=check) - if self.parent()._box is None: - if pp: - self._max_x = len(pp) - self._max_y = len(pp[0]) - self._max_z = pp[0][0] - else: - self._max_x = 0 - self._max_y = 0 - self._max_z = 0 + if self.parent()._box is None: + if pp: + self._max_x = len(pp) + self._max_y = len(pp[0]) + self._max_z = pp[0][0] else: - (self._max_x, self._max_y, self._max_z) = self.parent()._box + self._max_x = 0 + self._max_y = 0 + self._max_z = 0 + else: + (self._max_x, self._max_y, self._max_z) = self.parent()._box def check(self): """ @@ -573,6 +573,7 @@ def transpose(self, tableau_only=False): is returned instead of a PlanePartition object. This will not necessarily have trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -588,10 +589,14 @@ def transpose(self, tableau_only=False): T[c][r] = z_tab[r][c] if tableau_only: return T - elif self._max_x != self._max_y: - raise ValueError("Tranpose only supports parents with symmetric dimensions") - else: + elif self.parent()._box == None or self.parent()._box[0] == self.parent()._box[1]: return type(self)(self.parent(), T, check=False) + new_box = (self.parent()._box[1],self.parent()._box[0],self.parent()._box[2]) + return PlanePartitions(new_box,symmetry=self.parent._symmetry) + # elif self._max_x != self._max_y: + # raise ValueError("Tranpose only supports parents with symmetric dimensions") + # else: + # return type(self)(self.parent(), T, check=False) def is_SPP(self): r""" @@ -676,6 +681,10 @@ def is_TSPP(self): def is_SCPP(self): r""" Return whether ``self`` is a self-complementary plane partition. + + + + EXAMPLES:: @@ -684,6 +693,9 @@ def is_SCPP(self): False sage: PP = PlanePartition([[4,4,4,4],[4,4,2,0],[4,2,0,0],[0,0,0,0]]) sage: PP.is_SCPP() + False + 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 """ return self.z_tableau() == self.complement(tableau_only=True) @@ -803,6 +815,8 @@ def to_order_ideal(self): count += 1 oi = Q.order_ideal(generate) return oi + + def maximal_boxes(self): """ @@ -988,6 +1002,7 @@ def __init__(self): sage: TestSuite(P).run() # long time """ self._box = None + self._symmetry = None super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) def __repr__(self): @@ -1034,6 +1049,7 @@ def __init__(self, box_size): """ super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) self._box = box_size + self._symmetry = None def __repr__(self): """ @@ -1210,6 +1226,7 @@ def __init__(self, n): self._n = n # self._box = (0,0,0) self._box = None + self._symmetry = None def _repr_(self): """ @@ -1335,7 +1352,8 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'SPP' def _repr_(self): return "Symmetric plane partitions inside a {} x {} x {} box".format( @@ -1485,7 +1503,8 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'CSPP' def _repr_(self): return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( @@ -1610,7 +1629,8 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'TSPP' def _repr_(self): return "Totally symmetric plane partitions inside a {} x {} x {} box".format( @@ -1723,7 +1743,8 @@ def __init__(self, box_size): # if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): # raise ValueError("box sides cannot all be odd") super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'SCPP' def _repr_(self): return "Self-complementary plane partitions inside a {} x {} x {} box".format( @@ -1918,7 +1939,8 @@ def __init__(self, box_size): # if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): # raise ValueError("box sides cannot all be odd") super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'TCPP' def _repr_(self): return "Transpose complement plane partitions inside a {} x {} x {} box".format( @@ -1982,7 +2004,8 @@ def __init__(self, box_size): if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): raise ValueError("box sides cannot all be odd") super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'SSCPP' def _repr_(self): return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( @@ -2007,7 +2030,7 @@ def cardinality(self): #Class 8 class PlanePartitions_CSTCPP(PlanePartitions): - +#Cyclically symmetric transpose complement partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -2030,7 +2053,8 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'CSTCPP' def _repr_(self): return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( @@ -2050,11 +2074,11 @@ def cardinality(self): return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range(1+(a/2)-1))) return Integer(0) -#Class 9 +# Class 9 class PlanePartitions_CSSCPP(PlanePartitions): - +# Cyclically symmetric self-complementary plane partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -2077,7 +2101,8 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'CSSCPP' def _repr_(self): return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( @@ -2102,7 +2127,7 @@ def cardinality(self): #Class 10 class PlanePartitions_TSSCPP(PlanePartitions): - +#Totally symmetric self-complementary plane partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -2127,7 +2152,8 @@ def __init__(self, box_size): if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): raise ValueError("invalid box size; must be (2r,2r,2r)") super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box=box_size + self._box = box_size + self._symmetry = 'TSSCPP' def _repr_(self): return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( From 8cbe343d2910c213ee496d00773a0620a6886f5b Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Mon, 8 Jun 2020 19:08:27 -0500 Subject: [PATCH 34/74] Checkpoint before implementing monomial ideal features --- src/sage/combinat/plane_partition.py | 66 +++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 03ea99376f8..ce0ba96c46a 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -528,6 +528,41 @@ def add_rightside(i, j, k): TP += add_leftside(self.x_tableau()[r][c], r, c) TP.axes(show=False) return TP + + def contains(self, PP): + """ + + Return ``True`` if ``PP`` is a plane partition that fits + inside ``self``. + + Specifically, ``self`` contains ``PP`` if, for all `i`, `j`, + the height of ``PP`` at `ij` is less than or equal to the + height of ``self`` at `ij`. + + EXAMPLES:: + + sage: P1 = PlanePartition([[5,4,3],[3,2,2],[1]]) + sage: P2 = PlanePartition([[3,2],[1,1],[0,0],[0,0]]) + sage: P3 = PlanePartition([[5,5,5],[2,1,0]]) + sage: P1.contains(P2) + True + sage: P2.contains(P1) + False + sage: P1.contains(P3) + False + sage: P3.contains(P2) + True + """ + PP = PlanePartition(PP) + if len(self) < len(PP): + return False + + for i in range(len(PP)): + if len(self[i]) < len(PP[i]): + return False + + return all([self[i][j] >= PP[i][j] for j in range(len(PP[i])) for i in range(len(PP))]) + def complement(self, tableau_only=False): # Complement needs to be more intelligent about which parent to return @@ -841,11 +876,16 @@ def maximal_boxes(self): oi = Q.order_ideal_generators(generate) return [list(oi_elem) for oi_elem in oi] - def cyclically_rotate(self): + def cyclically_rotate(self, preserve_parent=False): """ Return the cyclic rotation of ``self``. - TODO: Ensure that parent is preserved under cyclic rotation. + By default, if the parent of ``self`` consists of plane + partitions inside an `a \times b \times c` box, the result + will have a parent consisting of partitions inside + a `c \times a \times b` box, unless the optional parameter + ``preserve_parents`` is set to ``True``. Enabling this setting + may give an element that is NOT an element of its parent. EXAMPLES:: @@ -856,6 +896,13 @@ def cyclically_rotate(self): Plane partition [[3, 1, 1, 1], [1]] sage: PP == PP.cyclically_rotate().cyclically_rotate().cyclically_rotate() True + sage: PP = PlanePartitions([4,3,2]).random_element() + sage: PP.cyclically_rotate().parent() + Plane partitions inside a 2 x 4 x 3 box + sage: PP = PlanePartitions([3,4,2])([[2,2,2,2],[2,2,2,2],[2,2,2,2]]) + sage: PP_rotated = PP.cyclically_rotate(preserve_parent=True) + sage: PP_rotated in PP_rotated.parent() + False """ (a, b, c) = (self._max_x, self._max_y, self._max_z) new_antichain = [] @@ -881,7 +928,12 @@ def cyclically_rotate(self): if j < c-1: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) - return PlanePartition(ppMatrix) + # Start code for determining correct parent + if self.parent()._box == None or preserve_parent == True or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): + return type(self)(self.parent(), ppMatrix, check=False) + new_box = (self.parent()._box[2],self.parent()._box[0],self.parent()._box[1]) + return PlanePartitions(new_box,symmetry=self.parent()._symmetry)(ppMatrix) + #return PlanePartition(ppMatrix) class PlanePartitions(UniqueRepresentation, Parent): r""" @@ -1600,12 +1652,13 @@ def cardinality(self): return Integer(numerator/denominator) -#Class 4 +# Class 4 class PlanePartitions_TSPP(PlanePartitions): +# Totally symmetric plane partitions -#Make sure inputs checked, code doesn't have a,b,c treated properly +# Make sure inputs checked, code doesn't have a,b,c treated properly @staticmethod def __classcall_private__(cls, box_size): @@ -1716,9 +1769,10 @@ def cardinality(self): -#Class 5 +# Class 5 class PlanePartitions_SCPP(PlanePartitions): +# Self-complementary plane partitions @staticmethod def __classcall_private__(cls, box_size): """ From af3be7e7982d9c52a4f276d8b526e30a478736af Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 20 Oct 2020 16:18:18 -0500 Subject: [PATCH 35/74] Revert "fixed minor merge conflict" This reverts commit 42b05de57e50040d0fdeece0c2d823e66c98942b, reversing changes made to 8eec238a732a321e53ed135141df44fa808588ab. --- src/sage/combinat/all.py | 2 - src/sage/combinat/plane_partition.py | 1752 ++------------------------ 2 files changed, 95 insertions(+), 1659 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index a39509b3bd0..aff242b60fb 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -134,8 +134,6 @@ lazy_import('sage.combinat.plane_partition', ('PlanePartition', 'PlanePartitions')) -#from .plane_partition import PlanePartition, PlanePartitions - # Parking Functions lazy_import('sage.combinat.non_decreasing_parking_function', ['NonDecreasingParkingFunctions', 'NonDecreasingParkingFunction']) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 62c4b340e04..b740d3cf198 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -24,20 +24,15 @@ #***************************************************************************** from __future__ import print_function, absolute_import -from sage.structure.list_clone import ClonableList +from sage.structure.list_clone import ClonableArray from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset -from sage.combinat.posets.poset_examples import posets -from sage.categories.cartesian_product import cartesian_product from sage.rings.integer import Integer from sage.misc.all import prod from sage.combinat.tableau import Tableau -from sage.arith.misc import Sigma -from sage.functions.other import floor, ceil, binomial, factorial class PlanePartition(ClonableArray, @@ -60,67 +55,48 @@ class PlanePartition(ClonableArray, The plane partition whose tableau representation is ``PP``. + EXAMPLES:: -@add_metaclass(InheritComparisonClasscallMetaclass) -class PlanePartition(ClonableList): + sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: PP + Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] + + TESTS:: + + sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: TestSuite(PP).run() + """ @staticmethod - def __classcall_private__(cls, PP): + def __classcall_private__(cls, PP, box_size=None): """ Construct a plane partition with the appropriate parent. EXAMPLES:: - sage: p = PlanePartition([[2,1],[1]]) - sage: TestSuite(p).run() - - sage: p.parent() - Plane partitions - sage: p.category() - Category of elements of Plane partitions - sage: type(p) - + sage: PP = PlanePartition([[4,3,3,1], [2,1,1], [1,1]]) + sage: PP.parent() is PlanePartitions((3,4,4)) + True """ - if isinstance(PP,PlanePartition): - return PP - pp = PlanePartitions() - return pp.element_class(pp, PP) # The check() will raise the appropriate error - - def __init__(self, parent, pp, check=True): - r""" - Initialize a plane partition. - - TESTS:: + if box_size is None: + if PP: + box_size = (len(PP), len(PP[0]), PP[0][0]) + else: + box_size = (0, 0, 0) + return PlanePartitions(box_size)(PP) - sage: a = PlanePartitions()([[2,1],[1]]) - sage: b = PlanePartitions([2,2,2])([[2,1],[1]]) - sage: c = PlanePartitions(4)([[2,1],[1]]) + def __init__(self, parent, PP, check=True): + """ + Initialize ``self``. - Add more tests to show which parent a,b,c receive, check that a==b, and b==c, but a is not b, and b is not c. + EXAMPLES:: + sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: TestSuite(PP).run() """ - if isinstance(pp, PlanePartition): - ClonableList.__init__(self, parent, pp, check=False) - else: - pp = [list(_) for _ 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) - - ClonableList.__init__(self, parent, pp, check=check) - if self.parent()._box is None: - if pp: - self._max_x = len(pp) - self._max_y = len(pp[0]) - self._max_z = pp[0][0] - else: - self._max_x = 0 - self._max_y = 0 - self._max_z = 0 - else: - (self._max_x, self._max_y, self._max_z) = self.parent()._box + ClonableArray.__init__(self, parent, PP, check=check) + self._max_x = parent._box[0] + self._max_y = parent._box[1] + self._max_z = parent._box[2] def check(self): """ @@ -128,25 +104,17 @@ def check(self): EXAMPLES:: - sage: a = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: a.check() - sage: b = PlanePartition([[1,2],[1]]) - Traceback (most recent call last): - ... - ValueError: Not weakly decreasing along rows - sage: c = PlanePartition([[1,1],[2]]) - Traceback (most recent call last): - ... - ValueError: Not weakly decreasing along columns + sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: PP.check() """ - for row in self: - if not all(c >= 0 for c in row): - raise ValueError("Entries not all nonnegative") - if not all(row[i] >= row[i+1] for i in range(len(row)-1)): - raise ValueError("Not weakly decreasing along rows") - for row, next in zip(self, self[1:]): - if not all(row[c] >= next[c] for c in range(len(next))): - raise ValueError("Not weakly decreasing along columns") + if len(self) == 0: + return + if len(self) > self.parent()._box[0]: + raise ValueError("too big in z direction") + if len(self[0]) > self.parent()._box[1]: + raise ValueError("too big in y direction") + if self[0][0] > self.parent()._box[2]: + raise ValueError("too big in x direction") def _repr_(self): """ @@ -233,18 +201,6 @@ def cells(self): L.append([r,c,h]) return L - def number_of_boxes(self): - r""" - Return the number of boxes in the plane partition. - - EXAMPLES:: - - sage: PP = PlanePartition([[3,1],[2]]) - sage: PP.number_of_boxes() - 6 - """ - return sum(sum(k for k in row) for row in self) - def _repr_diagram(self, show_box=False, use_unicode=False): r""" Return a string of the 3D diagram of ``self``. @@ -546,61 +502,16 @@ def add_rightside(i, j, k): TP += add_leftside(self.x_tableau()[r][c], r, c) TP.axes(show=False) return TP - - def contains(self, PP): - """ - - Return ``True`` if ``PP`` is a plane partition that fits - inside ``self``. - - Specifically, ``self`` contains ``PP`` if, for all `i`, `j`, - the height of ``PP`` at `ij` is less than or equal to the - height of ``self`` at `ij`. - - EXAMPLES:: - - sage: P1 = PlanePartition([[5,4,3],[3,2,2],[1]]) - sage: P2 = PlanePartition([[3,2],[1,1],[0,0],[0,0]]) - sage: P3 = PlanePartition([[5,5,5],[2,1,0]]) - sage: P1.contains(P2) - True - sage: P2.contains(P1) - False - sage: P1.contains(P3) - False - sage: P3.contains(P2) - True - """ - PP = PlanePartition(PP) - if len(self) < len(PP): - return False - - for i in range(len(PP)): - if len(self[i]) < len(PP[i]): - return False - - return all([self[i][j] >= PP[i][j] for j in range(len(PP[i])) for i in range(len(PP))]) - def complement(self, tableau_only=False): - # Complement needs to be more intelligent about which parent to return r""" Return the complement of ``self``. - If the parent of ``self`` consists only of partitions inside a given - box, then the complement is taken in this box. Otherwise, the - complement is taken in the smallest box containing the plane partition. - - If ``tableau_only`` is set to ``True``, then only the tableau - consisting of the projection of boxes size onto the xy-plane - is returned instead of a PlanePartition object. This output will - not have empty trailing rows or trailing zeros removed. - EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.complement() - Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1]] + Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] sage: PP.complement(True) [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] """ @@ -621,17 +532,11 @@ def transpose(self, tableau_only=False): r""" Return the transpose of ``self``. - If ``tableau_only`` is set to ``True``, then only the tableau - consisting of the projection of boxes size onto the xy-plane - is returned instead of a PlanePartition object. This will - not necessarily have trailing rows or trailing zeros removed. - - EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.transpose() - Plane partition [[4, 2, 1], [3, 1, 1], [3, 1], [1]] + Plane partition [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] sage: PP.transpose(True) [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] """ @@ -642,14 +547,8 @@ def transpose(self, tableau_only=False): T[c][r] = z_tab[r][c] if tableau_only: return T - elif self.parent()._box == None or self.parent()._box[0] == self.parent()._box[1]: + else: return type(self)(self.parent(), T, check=False) - new_box = (self.parent()._box[1],self.parent()._box[0],self.parent()._box[2]) - return PlanePartitions(new_box,symmetry=self.parent._symmetry) - # elif self._max_x != self._max_y: - # raise ValueError("Tranpose only supports parents with symmetric dimensions") - # else: - # return type(self)(self.parent(), T, check=False) def is_SPP(self): r""" @@ -734,10 +633,6 @@ def is_TSPP(self): def is_SCPP(self): r""" Return whether ``self`` is a self-complementary plane partition. - - - - EXAMPLES:: @@ -746,12 +641,9 @@ def is_SCPP(self): False sage: PP = PlanePartition([[4,4,4,4],[4,4,2,0],[4,2,0,0],[0,0,0,0]]) sage: PP.is_SCPP() - False - 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 """ - return self.z_tableau() == self.complement(tableau_only=True) + return self.z_tableau() == self.complement(True) def is_TCPP(self): r""" @@ -841,257 +733,29 @@ def is_TSSCPP(self): """ return self.is_TSPP() and self.is_SCPP() - def to_order_ideal(self): - """ - Return the order ideal corresponding to ``self``. - - TODO: As many families of symmetric plane partitions are in bijection - with order ideals in an associated poset, this function could - feasibly have options to send symmetric plane partitions - to the associated order ideal in that poset, instead. - - EXAMPLES:: - - sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() - [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] - sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() - [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] - """ - (a, b, c) = (self._max_x, self._max_y, self._max_z) - Q = posets.ProductOfChains([a,b,c]) - count = 0 - generate = [] - for i in range(len(self)): - for j in range(len(self[i])): - if (self[i][j] > 0): - generate.append((i,j,self[i][j]-1)) - count += 1 - oi = Q.order_ideal(generate) - return oi - - - - def maximal_boxes(self): - """ - Return the coordinates of the maximal boxes of ``self``. - - EXAMPLES:: - - sage: PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes() - [[0, 2, 0], [1, 1, 1], [0, 0, 2], [2, 0, 1]] - sage: PlanePartition([[2,1],[1],[1]]).maximal_boxes() - [[0, 1, 0], [0, 0, 1], [2, 0, 0]] - """ - (a, b, c) = (self._max_x, self._max_y, self._max_z) - Q = posets.ProductOfChains([a,b,c]) - count = 0 - generate = [] - for i in range(len(self)): - for j in range(len(self[i])): - if (self[i][j] > 0): - generate.append((i,j,self[i][j]-1)) - count+=1 - oi = Q.order_ideal_generators(generate) - return [list(oi_elem) for oi_elem in oi] - - def cyclically_rotate(self, preserve_parent=False): - """ - Return the cyclic rotation of ``self``. - - By default, if the parent of ``self`` consists of plane - partitions inside an `a \times b \times c` box, the result - will have a parent consisting of partitions inside - a `c \times a \times b` box, unless the optional parameter - ``preserve_parents`` is set to ``True``. Enabling this setting - may give an element that is NOT an element of its parent. - - EXAMPLES:: - - sage: PlanePartition([[3,2,1],[2,2],[2]]).cyclically_rotate() - Plane partition [[3, 3, 1], [2, 2], [1]] - sage: PP = PlanePartition([[4,1],[1],[1]]) - sage: PP.cyclically_rotate() - Plane partition [[3, 1, 1, 1], [1]] - sage: PP == PP.cyclically_rotate().cyclically_rotate().cyclically_rotate() - True - sage: PP = PlanePartitions([4,3,2]).random_element() - sage: PP.cyclically_rotate().parent() - Plane partitions inside a 2 x 4 x 3 box - sage: PP = PlanePartitions([3,4,2])([[2,2,2,2],[2,2,2,2],[2,2,2,2]]) - sage: PP_rotated = PP.cyclically_rotate(preserve_parent=True) - sage: PP_rotated in PP_rotated.parent() - False - """ - (a, b, c) = (self._max_x, self._max_y, self._max_z) - new_antichain = [] - for elem in self.maximal_boxes(): - new = (elem[1], elem[2], elem[0]) - new_antichain.append(new) - ppMatrix = [[0] * (c) for i in range(b)] - for box in new_antichain: - y = box[0] - z = box[1] - x = box[2] - ppMatrix[y][z] = (x+1) - if new_antichain != []: - for i in range(b): - i = b-(i+1) - for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): - iValue = 0 - jValue = 0 - if i < b-1: - iValue = ppMatrix[i+1][j] - if j < c-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - # Start code for determining correct parent - if self.parent()._box == None or preserve_parent == True or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): - return type(self)(self.parent(), ppMatrix, check=False) - new_box = (self.parent()._box[2],self.parent()._box[0],self.parent()._box[1]) - return PlanePartitions(new_box,symmetry=self.parent()._symmetry)(ppMatrix) - #return PlanePartition(ppMatrix) - class PlanePartitions(UniqueRepresentation, Parent): r""" - A factory class for plane partitions. - - PlanePartitions([a,b,c]) returns the class of plane partitions that fit - inside an a \times b \times c box. - - Optional keyword is 'symmetry'. - - Describe options. - - """ - @staticmethod - def __classcall_private__(cls, *args, **kwds): - r""" - This is a factory class which returns the appropriate parent based on - arguments. See the documentation for :class:`PlanePartitions` - for more information. - - TESTS:: - - sage: PlanePartitions() - Plane partitions - sage: PlanePartitions([3,3,3]) - Plane partitions inside a 3 x 3 x 3 box - sage: PlanePartitions(3) - 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 - """ - symmetry = kwds.get('symmetry', None) - if not args: - return PlanePartitions_all() - else: - box_size = None - if args: - # The first arg could be either a size or a box size - if isinstance(args[0], (int, Integer)): - return PlanePartitions_n(args[0]) - else: - box_size = args[0] - if symmetry == None: - return PlanePartitions_box(box_size) - elif symmetry == 'SPP': - return PlanePartitions_SPP(box_size) - elif symmetry == 'CSPP': - return PlanePartitions_CSPP(box_size) - elif symmetry == 'TSPP': - return PlanePartitions_TSPP(box_size) - elif symmetry == 'SCPP': - return PlanePartitions_SCPP(box_size) - elif symmetry == 'TCPP': - return PlanePartitions_TCPP(box_size) - elif symmetry == 'SSCPP': - return PlanePartitions_SSCPP(box_size) - elif symmetry == 'CSTCPP': - return PlanePartitions_CSTCPP(box_size) - elif symmetry == 'CSSCPP': - return PlanePartitions_CSSCPP(box_size) - elif symmetry == 'TSSCPP': - return PlanePartitions_TSSCPP(box_size) - else: - raise ValueError("invalid symmetry class option; must be None, 'SPP', 'CSPP', 'TSPP', 'SCPP', 'TCPP', 'SSCPP', 'CSTCPP', 'CSSCPP', or 'TSSCPP' ") - - - Element = PlanePartition - - - def __contains__(self, pp): - """ - Check to see that ``self`` is a valid plane partition. - - .. TODO: - - Figure out how redundant this is, given that the check function - exists for the factor class. Maybe only need __contains__ - on the fixed size and symmetry classes? - """ - for row in pp: - if not all(c >= 0 for c in row): - return False - if not all(row[i] >= row[i+1] for i in range(len(row)-1)): - return False - for row, next in zip(pp, pp[1:]): - if not all(row[c] >= next[c] for c in range(len(next))): - return False - return True - - - - - -class PlanePartitions_all(PlanePartitions): - r""" - All plane partitions. - - .. TODO: - - Consider giving this the structure of disjoint union of the classes - PlanePartitions(n) for n an integer. - """ + All plane partitions inside a rectangular box of given side lengths. + INPUT: - def __init__(self): - r""" - Initializes the class of all plane partitions. - - .. WARNING:: - - Input is not checked; please use :class:`PlanePartitions` to - ensure the options are properly parsed. - - TESTS:: - - sage: from sage.combinat.plane_partition import PlanePartitions_all - sage: P = PlanePartitions_all() - sage: TestSuite(P).run() # long time - """ - self._box = None - self._symmetry = None - super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) - - def __repr__(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: + - ``box_size`` -- a triple of positive integers indicating the size + of the box containing the plane partition - sage: PlanePartitions() - Plane partitions - """ - return "Plane partitions" + EXAMPLES: + This will create an instance to manipulate the plane partitions + in a `4 \times 3 \times 2` box:: + sage: P = PlanePartitions((4,3,2)) + sage: P + Plane partitions inside a 4 x 3 x 2 box + sage: P.cardinality() + 490 + .. SEEALSO:: -class PlanePartitions_box(PlanePartitions): - r""" - All plane partitions that fit inside a box of a specified size. + :class:`PlanePartition` """ @staticmethod def __classcall_private__(cls, box_size): @@ -1105,23 +769,23 @@ def __classcall_private__(cls, box_size): sage: P1 is P2 True """ - return super(PlanePartitions_box, cls).__classcall__(cls, tuple(box_size)) + return super(PlanePartitions, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): r""" - Initializes the class of plane partitions that fit in a box of a - specified size. + Initialize ``self`` EXAMPLES:: sage: PP = PlanePartitions((4,3,2)) sage: TestSuite(PP).run() """ - super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) + if len(box_size) != 3: + raise ValueError("invalid box size") self._box = box_size - self._symmetry = None + Parent.__init__(self, category=FiniteEnumeratedSets()) - def __repr__(self): + def _repr_(self): """ Return a string representation of ``self``. @@ -1130,87 +794,30 @@ def __repr__(self): sage: PlanePartitions((4,3,2)) Plane partitions inside a 4 x 3 x 2 box """ - return "Plane partitions inside a %s x %s x %s box" % (self._box[0], self._box[1], self._box[2]) - - def __contains__(self, x): - if len(x) == 0: - return True - return PlanePartitions.__contains__(self, x) and len(x) <= self._box[0] and len(x[0]) <= self._box[1] and x[0][0] <= self._box[2] - - def to_poset(self): - r""" - Returns the product of three chains poset, whose order ideals are - naturally in bijection with plane partitions inside a box. - """ - a=self._box[0] - b=self._box[1] - c=self._box[2] - return posets.ProductOfChains([a,b,c]) - - def from_order_ideal(self, I): - r""" - Return the plane partition corresponding to an order ideal in the - poset given in :meth:`to_poset`. - - Note: input may not be checked ? Optional check parameter if too much overhead? - """ - return self.from_antichain(self.to_poset().order_ideal_generators(I)) - - def from_antichain(self, A): - r""" - Return the plane partition corresponding to an antichain in the poset - given in :meth:`to_poset`. - - Note: input may not be checked? Optional parameter if too much overhead? - """ - a = self._box[0] - b = self._box[1] - c = self._box[2] - ppMatrix = [[0] * (b) for i in range(a)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - - #ac format ex: [x,y,z] - #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) - for ac in A: - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix[x][y] = (z+1) - - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format - if A != []: - for i in range(a): - i = a-(i+1) - for j in range(b): - j = b-(j+1) - if (ppMatrix[i][j] == 0): - iValue = 0 - jValue = 0 - if i < a-1: - iValue = ppMatrix[i+1][j] - if j < b-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - return self.element_class(self, ppMatrix) - + return "Plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) def __iter__(self): - r""" + """ Iterate over ``self``. EXAMPLES:: sage: list(PlanePartitions((1,2,1))) - [Plane partition [], Plane partition [[1, 1]], Plane partition [[1]]] + [Plane partition [[0, 0]], + Plane partition [[1, 0]], + Plane partition [[1, 1]]] """ - a = self._box[0] - b = self._box[1] - c = self._box[2] - pocp = posets.ProductOfChains([a,b,c]) - matrixList = [] #list of all PlanePartitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with parameters (a,b,c) - for acl in self.to_poset().antichains_iterator(): - yield self.from_antichain(acl) - + A = self._box[0] + B = self._box[1] + C = self._box[2] + from sage.combinat.tableau import SemistandardTableaux + for T in SemistandardTableaux([B for i in range(A)], max_entry=C+A): + PP = [[0 for i in range(B)] for j in range(A)] + for r in range(A): + for c in range(B): + PP[A-1-r][B-1-c] = T[r][c] - r - 1 + yield self.element_class(self, PP, check=False) def cardinality(self): r""" @@ -1239,8 +846,8 @@ def cardinality(self): def box(self): """ - Return the size of the box of the plane partition of ``self`` - is contained in. + Return the sizes of the box of the plane partitions of ``self`` + are contained in. EXAMPLES:: @@ -1263,1188 +870,19 @@ def random_element(self): EXAMPLES:: sage: P = PlanePartitions((4,3,5)) - sage: P.random_element() - Plane partition [[4, 3, 3], [4], [2]] - """ - Z = self.from_order_ideal(self.to_poset().random_order_ideal()) - return self.element_class(self, Z, check=False) - - - -class PlanePartitions_n(PlanePartitions): - """ - Plane partitions with a fixed number of boxes. - """ - - def __init__(self, n): - r""" - Initializes the class of plane partitions with ``n`` boxes. - - .. WARNING:: - - Input is not checked; please use :class:`PlanePartitions` to - ensure the options are properly parsed. (CHECK: does this make sense?) - - TESTS:: - - sage: PP = PlanePartitions(4) - sage: type(PP) - - sage: TestSuite(PP).run() - """ - super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) - self._n = n -# self._box = (0,0,0) - self._box = None - self._symmetry = None - - def _repr_(self): - """ - TESTS:: - - sage: PlanePartitions(3) - Plane partitions of size 3 - """ - return "Plane partitions of size {}".format(self._n) - - def __contains__(self, x): - return PlanePartitions.__contains__(self, x) and x.number_of_boxes() == self._n - - def __iter__(self): - r""" - An iterator to generate all plane partitions of a fixed size. - - EXAMPLES:: - - sage: list(PlanePartitions(2)) - [Plane partition [[2]], Plane partition [[1, 1]], Plane partition [[1], [1]]] - """ - from sage.combinat.partition import Partitions - def PP_first_row_iter(n, la): - m = n-sum(la) - if m < 0: - yield - return - if m==0: - yield [la] - return - for k in range(m,0,-1): - for mu in P_in_shape_iter(k,la): - if mu is not None: - for PP in PP_first_row_iter(m, mu): - if PP is not None: - yield [la] + PP - - - def P_in_shape_iter(n, la): - if n<0 or sum(la)=n: - yield [n] - return - else: - yield - return - if sum(la)==n: - yield la - return - for mu_0 in range(min(n,la[0]),0,-1): - new_la = [min(mu_0,la[i]) for i in range(1,len(la))] - for mu in P_in_shape_iter(n-mu_0, new_la): - if mu is not None: - yield [mu_0]+mu - n = self._n - if n==0: - yield PlanePartition([]) - return - - for m in range(n,0,-1): - for la in Partitions(m): - for a in PP_first_row_iter(n,la): - yield self.element_class(self, a, check=False) - - def cardinality(self): - r""" - Return the number of plane partitions with ``n`` boxes. - - Calculated using the recurrence relation - - .. MATH: - - PL(n) = \sum_{k=1}^n PL(n-k)\sigma_2(k) - - where ``\sigma_k(n)`` is the sum of the kth powers of - divisors of n. - - """ - PPn = [1] - for i in range(1,1+self._n): - nextPPn = sum(PPn[i-k]*Sigma()(k,2) for k in range(1,i+1))/i - PPn.append(nextPPn) - return(Integer(PPn[-1])) - -#Symmetry classes are enumerated and labelled in order as in Proofs and -#Confirmations/Stanley (with all plane partitions being the first class) - - - - -#Class 2 - -class PlanePartitions_SPP(PlanePartitions): - -#How to handle when a!=b ? - - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((3,3,2), symmetry='SPP') - sage: P2 = PlanePartitions([3,3,2], symmetry='SPP') - sage: P1 is P2 + sage: p = P.random_element() + sage: p.parent() is P True """ - return super(PlanePartitions_SPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,2], symmetry='SPP') - sage: TestSuite(PP).run() - """ - super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'SPP' - - def _repr_(self): - return "Symmetric plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def __contains__(self, x): - return PlanePartitions.__contains__(self, x) and x.is_SPP() - - - def to_poset(self): - r""" - Returns a poset whose order ideals are in bijection with - symmetric plane partitions. - """ - a=self._box[0] - b=self._box[1] - c=self._box[2] - pl = [] - cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) - for x in range(0,a): - for y in range(0,x+1): - for z in range(0,c): - pl.append((x,y,z)) - return Poset((pl,cmp)) - - def from_order_ideal(self, I): - r""" - Return the plane partition corresponding to an order ideal in the - poset given in :meth:`to_poset()`. - - Note: input may not be checked ? Optional check parameter if too much overhead? - """ - return self.from_antichain(self.to_poset().order_ideal_generators(I)) - - def from_antichain(self, A): - r""" - Return the plane partition corresponding to an antichain in the poset - given in :meth:`to_poset()`. - - Note: input may not be checked? Optional parameter if too much overhead? - """ - #Initialize an empty plane partition - a=self._box[0] - b=self._box[1] - c=self._box[2] - ppMatrix = [[0] * (b) for i in range(a)] - #Antichain indicates where the 'corners' will be in the - #plane partition - for ac in A: - x=ac[0] - y=ac[1] - z=ac[2] - ppMatrix[x][y] = (z+1) - #Fill out the rest of the plane partition using symmetry and the - #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) - if A!= []: - for i in range(a): - i = a-(i+1) - for j in range(b): - j = b-(j+1) - if (ppMatrix[i][j] == 0) and i>=j: - iValue = 0 - jValue = 0 - if i < a-1: - iValue = ppMatrix[i+1][j] - if j < b-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - elif j>i: - ppMatrix[i][j] = ppMatrix[j][i] - return self.element_class(self, ppMatrix) - - def __iter__(self): - for acl in self.to_poset().antichains_iterator(): - yield self.from_antichain(acl) - - def cardinality(self): - r""" - Return the cardinality of ``self``. - - The number of symmetric plane partitions inside an `r \times r \times t` - box is equal to - - .. MATH:: - - \prod_{i=1}^{r} \frac{2*i + t - 1}{2*i - 1} * - \prod_{1 \leq i \leq j \leq r} \frac{i+j+t-1}{i+j-1} - - EXAMPLES:: - - sage: P = PlanePartitions((3,3,2), symmetry='SPP') - sage: P.cardinality() - 35 - """ - A = self._box[0] - B = self._box[1] - C = self._box[2] - leftProduct = (prod( (2*i + C - 1) / (2*i - 1) for i in range(1,A+1))) - rightProduct = (prod( (i + j + C - 1) / (i + j - 1) for j in range(1, A+1) for i in range(1, j) )) - return Integer(leftProduct * rightProduct) - - def random_element(self): - r""" - Return a uniformly random element of ``self``. - - ALGORITHM: - - This uses the - :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` - method and the natural bijection between symmetric plane partitions - and antichains in an associated poset. (FIX EXAMPLES) - - EXAMPLES:: - - sage: P = PlanePartitions((4,3,5)) - sage: P.random_element() - Plane partition [[4, 3, 3], [4], [2]] - """ - Z = self.from_order_ideal(self.to_poset().random_order_ideal()) + def leq(thing1, thing2): + return all(thing1[i] <= thing2[i] for i in range(len(thing1))) + elem = [(i,j,k) for i in range(self._box[0]) for j in range(self._box[1]) + for k in range(self._box[2])] + myposet = Poset((elem, leq)) + R = myposet.random_order_ideal() + Z = [[0 for i in range(self._box[1])] for j in range(self._box[0])] + for C in R: + Z[C[0]][C[1]] += 1 return self.element_class(self, Z, check=False) -#Class 3 - -class PlanePartitions_CSPP(PlanePartitions): - -#For some reason works if not(a == b == c) - - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,3,2), symmetry='CSPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='CSPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') - sage: TestSuite(PP).run() - """ - super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'CSPP' - - def _repr_(self): - return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def to_poset(self): - """ - MAKE SURE DOC EXPLICITLY DESCRIBES WHAT FUNDAMENTAL DOMAIN LOOKS LIKE - """ - a=self._box[0] - b=self._box[1] - c=self._box[2] - cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) - cmp2 = lambda x,y : cmp(x,y) or cmp(x,(y[2],y[0],y[1])) or cmp(x,(y[1],y[2],y[0])) - pl = [] - for x in range(0,a): - for y in range(0, b): - for z in range(x,c): - if y <= z and (x != z or y == x): - pl.append((x,y,z)) - return Poset((pl, cmp2)) - - def from_antichain(self, acl): - a=self._box[0] - b=self._box[1] - c=self._box[2] - ppMatrix = [[0] * (c) for i in range(b)] - #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - #ac format ex: [x,y,z] - for ac in acl: - x = ac[0] - y = ac[1] - z = ac[2] - ppMatrix[y][z] = (x+1) - ppMatrix[z][x] = (y+1) - ppMatrix[x][y] = (z+1) - - - #for each value in current antichain, fill in the rest of the - #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is - #now in plane partition format - if acl != []: - for i in range(b): - i = b-(i+1) - for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): - iValue = 0 - jValue = 0 - if i < b-1: - iValue = ppMatrix[i+1][j] - if j < c-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - return self.element_class(self, ppMatrix) - - def from_order_ideal(self, I): - r""" - Return the plane partition corresponding to an order ideal in the - poset given in :meth:`to_poset`. - - Note: input may not be checked ? Optional check parameter if too much overhead? - """ - return self.from_antichain(self.to_poset().order_ideal_generators(I)) - - def __iter__(self): - for acl in self.to_poset().antichains_iterator(): - yield self.from_antichain(acl) - - def cardinality(self): - r""" - Return the cardinality of ``self``. - - The number of cyclically symmetric plane partitions inside an - `r \times r \times r` box is equal to - - .. MATH:: - - \left(\prod_{i=1}^{r} \frac{3i - 1}{3i - 2}\right) - \left(\prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{2i+j-1}\right) - - EXAMPLES:: - - sage: P = PlanePartitions((4,4,4), symmetry='CSPP') - sage: P.cardinality() - 132 - """ - A = self._box[0] - B = self._box[1] - C = self._box[2] - 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) - - -# Class 4 - - -class PlanePartitions_TSPP(PlanePartitions): -# Totally symmetric plane partitions - -# Make sure inputs checked, code doesn't have a,b,c treated properly - - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,3,2), symmetry='TSPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='TSPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') - sage: TestSuite(PP).run() - """ - super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'TSPP' - - def _repr_(self): - return "Totally symmetric plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def to_poset(self): - a=self._box[0] - b=self._box[1] - c=self._box[2] - cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) - pl = [] - for x in range(0,a): - for y in range(x, b): - for z in range(y,c): - pl.append((x,y,z)) - return Poset((pl,cmp)) - - def from_antichain(self, acl): - a=self._box[0] - b=self._box[1] - c=self._box[2] - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - for ac in acl: - x = ac[0] - y = ac[1] - z = ac[2] - - - ppMatrix[y][z] = (x+1) #x,y,z - ppMatrix[z][x] = (y+1) #y,z,x - ppMatrix[x][y] = (z+1) #z,x,y - - ppMatrix[z][y] = (x+1) #x,z,y - ppMatrix[x][z] = (y+1) #y,x,z - ppMatrix[y][x] = (z+1) #z,y,x - - - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format - if acl != []: - for i in range(b): - i = b-(i+1) - for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): - iValue = 0 - jValue = 0 - if i < b-1: - iValue = ppMatrix[i+1][j] - if j < c-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - return self.element_class(self, ppMatrix) - - def random_element(self): - return self.to_poset().from_antichain(self.to_poset().random_antichain()) - - def __iter__(self): - for A in self.to_poset().antichains_iterator(): - yield self.from_antichain(A) - - - def cardinality(self): - r""" - Return the cardinality of ``self``. - - The number of totally symmetric plane partitions inside an - `r \times r \times r` box is equal to - - .. MATH:: - - \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{i+2j-2} - - EXAMPLES:: - - sage: P = PlanePartitions((4,4,4), symmetry='TSPP') - sage: P.cardinality() - 66 - """ - A = self._box[0] - B = self._box[1] - C = self._box[2] - 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) )) - - - -# Class 5 - -class PlanePartitions_SCPP(PlanePartitions): -# Self-complementary plane partitions - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,3,2), symmetry='SCPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='SCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') - sage: TestSuite(PP).run() - """ -# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): -# raise ValueError("box sides cannot all be odd") - super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'SCPP' - - def _repr_(self): - return "Self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def __iter__(self): - a=self._box[0] - b=self._box[1] - c=self._box[2] - def Partitions_inside_lambda(la): - "Returns the list of partitions contained in la with the same number of parts including 0s." - if len(la)==0: - yield [] - return - LIST = [] - 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 for i in la] - return - - def Partitions_inside_lambda_with_smallest_at_least_k(la,k): - "Returns the list of partitions contained in la with the smallest entry at least k" - if len(la)==0: - yield [] - return - if la[-1] < k: - yield - return - LIST = [] - for mu in Partitions_inside_lambda([la[i]-k for i in range(len(la))]): - yield ([mu[i]+k for i in range(len(la))]) - return - - def possible_middle_row_for_b_odd(a,c): - "Returns the list of possible middle row for SCPP inside box(a,b,c) when b is odd" - if a*c % 2 == 1: - yield - return - LIST = [] - for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor(a/2))]): - nu = [c-mu[len(mu)-1-i] for i in range(len(mu))] - if a % 2 ==0: - la = nu + mu - else: - la = nu + [c/2] + mu - yield (la) - return - - def possible_middle_row_for_b_even(a,c): - "Returns the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" - LIST = [] - for mu in Partitions_inside_lambda([floor(c/2) for i in range((a+1)/2)]): - nu = [c-mu[len(mu)-1-i] for i in range(floor(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): - "Returns PPs with first row la and with k rows in total" - if k == 0: - yield [] - return - if k == 1: - yield [la] - return - LIST = [] - 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): - "Returns the complement of PP with respect to height c" - if len(PP) == 0: - return [] - b = len(PP) - a = len(PP[0]) - return [[c-PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] - - if a*b*c % 2 == 1: - return - - if b % 2 == 1: - for la in possible_middle_row_for_b_odd(a,c): # la is the middle row of SCPP - 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 - 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): - r""" - Return the cardinality of ``self``. - - The number of self complementary plane partitions inside a - `2a \times 2b \times 2c` box is equal to - - .. MATH:: - - \left(\prod_{i=1}^{r}\prod_{j=1}^{b} \frac{i + j + c - 1}{i + j - 1}\right)^2 - - - - The number of self complementary plane partitions inside an - `(2a+1) \times 2b \times 2c` box is equal to - - .. MATH:: - - \left(\prod_{i=1}^{a}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - - - The number of self complementary plane partitions inside an - `(2a+1) \times (2b+1) \times 2c` box is equal to - - .. MATH:: - - \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - \left(\prod_{i=1}^{a}\prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right) - - EXAMPLES:: - - sage: P = PlanePartitions((4,4,4), symmetry='SCPP') - sage: P.cardinality() - 400 - - sage: P = PlanePartitions((5,4,4), symmetry='SCPP') - sage: P.cardinality() - 1000 - - sage: P = PlanePartitions((5,5,4), symmetry='SCPP') - sage: P.cardinality() - 2500 - """ - r=self._box[0] - s=self._box[1] - t=self._box[2] - if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) - if r % 2 == 1 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+t/2)))) - if r % 2 == 0 and s % 2 == 1 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) - if r % 2 == 0 and s % 2 == 0 and t % 2 == 1: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) - if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) - if r % 2 == 1 and s % 2 == 0 and t % 2 == 1: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) - if r % 2 == 0 and s % 2 == 1 and t % 2 == 1: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+(t-1)/2+1)))) - if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: - return Integer(0) - - -#Class 6 - -class PlanePartitions_TCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,3,2), symmetry='TCPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='TCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_TCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry='TCPP') - sage: TestSuite(PP).run() - """ -# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): -# raise ValueError("box sides cannot all be odd") - super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'TCPP' - - def _repr_(self): - return "Transpose complement plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def __iter__(self): - for p in PlanePartitions(self._box): - if p.is_TCPP(): - yield self.element_class(self,p) - return - - - - def cardinality(self): - r""" - Return the cardinality of ``self``. - - The number of transpose complement plane partitions inside an - `a \times a \times 2b` box is equal to - - .. MATH:: - - \binom{b+1-1}{a-1}\prod_{1\leq i\leq j a-2} \frac{i + j + 2b - 1}{i + j - 1} - """ - - a=self._box[0] - b=self._box[1] - c=self._box[2] - if a==b and c % 2 == 0: - 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))) - else: - return Integer(0) - -#Class 7 - -class PlanePartitions_SSCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,4,2), symmetry='SSCPP') - sage: P2 = PlanePartitions([4,4,2], symmetry='SSCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_SSCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') - sage: TestSuite(PP).run() - """ - -#Think about how to check a=b and not all a,b,c odd - - if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("box sides cannot all be odd") - super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'SSCPP' - - def _repr_(self): - return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def __iter__(self): - for p in PlanePartitions(self._box): - if p.is_SSCPP(): - yield self.element_class(self,p) - return - - def cardinality(self): - r=self._box[0] - s=self._box[1] - t=self._box[2] - if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+r/2) for k in range(1,1+t/2)))) - if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+(r-1)/2) for j in range(1,1+((r-1)/2)+1) for k in range(1,1+t/2)))) - return Integer(0) - -#Class 8 - -class PlanePartitions_CSTCPP(PlanePartitions): -#Cyclically symmetric transpose complement partitions - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((3,3,3), symmetry='CSTCPP') - sage: P2 = PlanePartitions([3,3,3], symmetry='CSTCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry='CSTCPP') - sage: TestSuite(PP).run() - """ - super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'CSTCPP' - - def _repr_(self): - return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def __iter__(self): - for p in PlanePartitions(self._box): - if p.is_CSTCPP(): - yield self.element_class(self,p) - return - - def cardinality(self): - a=self._box[0] - b=self._box[1] - c=self._box[2] - if a == b and b == c and a % 2 == 0: - return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range(1+(a/2)-1))) - return Integer(0) - -# Class 9 - - -class PlanePartitions_CSSCPP(PlanePartitions): -# Cyclically symmetric self-complementary plane partitions - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((3,3,3), symmetry='CSSCPP') - sage: P2 = PlanePartitions([3,3,3], symmetry='CSSCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([3,3,3], symmetry='CSSCPP') - sage: TestSuite(PP).run() - """ - super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'CSSCPP' - - def _repr_(self): - return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def __iter__(self): - for p in PlanePartitions(self._box): - if p.is_CSSCPP(): - yield self.element_class(self,) - return - - def cardinality(self): - a=self._box[0] - b=self._box[1] - c=self._box[2] - if a == b and b == c and a % 2 == 0: - return Integer(prod( ((factorial(3*i+1)**2/(factorial(a+i)**2) for i in range((a/2)))))) - return Integer(0) - - - -#Class 10 - -class PlanePartitions_TSSCPP(PlanePartitions): -#Totally symmetric self-complementary plane partitions - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,4,4), symmetry='TSSCPP') - sage: P2 = PlanePartitions([4,4,4], symmetry='TSSCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_TSSCPP, cls).__classcall__(cls, tuple(box_size)) - - def __init__(self, box_size): - """ - TESTS:: - - sage: PP = PlanePartitions([4,4,4], symmetry='TSSCPP') - sage: TestSuite(PP).run() - """ - if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): - raise ValueError("invalid box size; must be (2r,2r,2r)") - super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'TSSCPP' - - def _repr_(self): - return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) - - def to_poset(self): - cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) - def componentwise_comparer(thing1,thing2): - if len(thing1) == len(thing2): - if all(thing1[i] <= thing2[i] for i in range(len(thing1))): - return True - return False - a=self._box[0] - b=self._box[1] - c=self._box[2] - if a != b or b != c or a != c: - return - - pl = [] - for x in range(0,a/2 - 2 + 1): - for y in range(x, a/2 - 2 + 1): - for z in range(0,a/2 - 2 + 1): - if z <= a/2 - 2 - y: - pl.append((x,y,z)) - - return Poset((pl,cmp)) - - def from_antichain(self, acl): - #ac format ex: [x,y,z] - a=self._box[0] - b=self._box[1] - c=self._box[2] - n=a - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] - width = n/2 - 1 - height = n/2 - 1 - - #generate inner triagle - for i in range(width): - for j in range(height): - if(i <= j): - for ac in acl: - if ac[0] == i and ac[1] == j: - zVal = ac[2] - matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] - if zVal + 1 > matrixVal: - ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 - - #fill back - for i in range(width): - i = width-(i+1) - i = i + n/2 - for j in range(height): - j = height-(j+1) - j = j + n/2 - if (ppMatrix[i][j] == 0): - if i >= j: - iValue = 0 - jValue = 0 - if i < n: - iValue = ppMatrix[i+1][j] - if j < n: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - - - #fill half of triangle symmetrically - for i in range(width): - i = i + n/2 - for j in range(height): - j = j + n/2 - if i >= j: - ppMatrix[j][i] = ppMatrix[i][j] - - #upper left box - for i in range(n/2): - for j in range(n/2): - ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] - - - #fill in lower left cube with values n/2 - for i in range(n/2): - for j in range(n/2): - x = i - y = j - if(ppMatrix[x][y+(n/2)]) == 0: - ppMatrix[x][y+(n/2)] = n/2 - if(ppMatrix[x+(n/2)][y]) == 0: - ppMatrix[x+(n/2)][y] = n/2 - - - #add and subtract values from lower left cube to be rotation of lower right cube - for i in range(n/2): - for j in range(n/2): - x = i+(n/2) - y = j+(n/2) - if ppMatrix[x][y] > 0: - z = ppMatrix[x][y] - for cVal in range(z): - #build onto lower left cube - ppMatrix[x][0+cVal] += 1 - #carve out of lower left cube - ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 - - #fill in upper right cube symmetrically with lower left - for i in range(n/2): - for j in range(n/2): - ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] - return self.element_class(self, ppMatrix) - - - - - - def __iter__(self): -# def componentwise_comparer(thing1,thing2): -# if len(thing1) == len(thing2): -# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): -# return True -# return False -# a=self._box[0] -# b=self._box[1] -# c=self._box[2] -# n = a -# b = n -# c = n - -# pl = [] -# for x in range(0,n/2 - 2 + 1): -# for y in range(x, n/2 - 2 + 1): -# for z in range(0,n/2 - 2 + 1): -# if z <= n/2 - 2 - y: -# pl.append((x,y,z)) - -# pocp = Poset((pl,componentwise_comparer)) -# cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) -# pocp = Poset((pl,cmp)) - -# matrixList = [] #list of all PlaneParitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with paramaters (a,b,c) - for acl in self.to_poset().antichains_iterator(): - yield self.from_antichain(acl) - return -# #ac format ex: [x,y,z] -# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] -# width = n/2 - 1 -# height = n/2 - 1 - -# #generate inner triagle -# for i in range(width): -# for j in range(height): -# if(i <= j): -# for ac in acl: -# if ac[0] == i and ac[1] == j: -# zVal = ac[2] -# matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] -# if zVal + 1 > matrixVal: -# ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 - -# #fill back -# for i in range(width): -# i = width-(i+1) -# i = i + n/2 -# for j in range(height): -# j = height-(j+1) -# j = j + n/2 -# if (ppMatrix[i][j] == 0): -# if i >= j: -# iValue = 0 -# jValue = 0 -# if i < n: -# iValue = ppMatrix[i+1][j] -# if j < n: -# jValue = ppMatrix[i][j+1] -# ppMatrix[i][j] = max(iValue,jValue) - - -# #fill half of triangle symmetrically -# for i in range(width): -# i = i + n/2 -# for j in range(height): -# j = j + n/2 -# if i >= j: -# ppMatrix[j][i] = ppMatrix[i][j] - -# #upper left box -# for i in range(n/2): -# for j in range(n/2): -# ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] - - -# #fill in lower left cube with values n/2 -# for i in range(n/2): -# for j in range(n/2): -# x = i -# y = j -# if(ppMatrix[x][y+(n/2)]) == 0: -# ppMatrix[x][y+(n/2)] = n/2 -# if(ppMatrix[x+(n/2)][y]) == 0: -# ppMatrix[x+(n/2)][y] = n/2 - - -# #add and subtract values from lower left cube to be rotation of lower right cube -# for i in range(n/2): -# for j in range(n/2): -# x = i+(n/2) -# y = j+(n/2) -# if ppMatrix[x][y] > 0: -# z = ppMatrix[x][y] -# for cVal in range(z): -# #build onto lower left cube -# ppMatrix[x][0+cVal] += 1 -# #carve out of lower left cube -# ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 - -# #fill in upper right cube symmetrically with lower left -# for i in range(n/2): -# for j in range(n/2): -# ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] -# yield self.element_class(self, ppMatrix) - - + Element = PlanePartition From bc38eef77ad4033b1e3357d0812a0ea1913722ef Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 13 Oct 2020 01:48:35 -0500 Subject: [PATCH 36/74] fixed minor merge conflict --- src/sage/combinat/all.py | 2 + src/sage/combinat/plane_partition.py | 1752 ++++++++++++++++++++++++-- 2 files changed, 1659 insertions(+), 95 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index aff242b60fb..a39509b3bd0 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -134,6 +134,8 @@ lazy_import('sage.combinat.plane_partition', ('PlanePartition', 'PlanePartitions')) +#from .plane_partition import PlanePartition, PlanePartitions + # Parking Functions lazy_import('sage.combinat.non_decreasing_parking_function', ['NonDecreasingParkingFunctions', 'NonDecreasingParkingFunction']) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index b740d3cf198..62c4b340e04 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -24,15 +24,20 @@ #***************************************************************************** from __future__ import print_function, absolute_import -from sage.structure.list_clone import ClonableArray +from sage.structure.list_clone import ClonableList from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset +from sage.combinat.posets.poset_examples import posets +from sage.categories.cartesian_product import cartesian_product from sage.rings.integer import Integer from sage.misc.all import prod from sage.combinat.tableau import Tableau +from sage.arith.misc import Sigma +from sage.functions.other import floor, ceil, binomial, factorial class PlanePartition(ClonableArray, @@ -55,48 +60,67 @@ class PlanePartition(ClonableArray, The plane partition whose tableau representation is ``PP``. - EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP - Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] - - TESTS:: - - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: TestSuite(PP).run() - """ +@add_metaclass(InheritComparisonClasscallMetaclass) +class PlanePartition(ClonableList): @staticmethod - def __classcall_private__(cls, PP, box_size=None): + def __classcall_private__(cls, PP): """ Construct a plane partition with the appropriate parent. EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1], [2,1,1], [1,1]]) - sage: PP.parent() is PlanePartitions((3,4,4)) - True - """ - if box_size is None: - if PP: - box_size = (len(PP), len(PP[0]), PP[0][0]) - else: - box_size = (0, 0, 0) - return PlanePartitions(box_size)(PP) + sage: p = PlanePartition([[2,1],[1]]) + sage: TestSuite(p).run() - def __init__(self, parent, PP, check=True): + sage: p.parent() + Plane partitions + sage: p.category() + Category of elements of Plane partitions + sage: type(p) + """ - Initialize ``self``. + if isinstance(PP,PlanePartition): + return PP + pp = PlanePartitions() + return pp.element_class(pp, PP) # The check() will raise the appropriate error - EXAMPLES:: + def __init__(self, parent, pp, check=True): + r""" + Initialize a plane partition. + + TESTS:: + + sage: a = PlanePartitions()([[2,1],[1]]) + sage: b = PlanePartitions([2,2,2])([[2,1],[1]]) + sage: c = PlanePartitions(4)([[2,1],[1]]) + + Add more tests to show which parent a,b,c receive, check that a==b, and b==c, but a is not b, and b is not c. - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: TestSuite(PP).run() """ - ClonableArray.__init__(self, parent, PP, check=check) - self._max_x = parent._box[0] - self._max_y = parent._box[1] - self._max_z = parent._box[2] + if isinstance(pp, PlanePartition): + ClonableList.__init__(self, parent, pp, check=False) + else: + pp = [list(_) for _ 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) + + ClonableList.__init__(self, parent, pp, check=check) + if self.parent()._box is None: + if pp: + self._max_x = len(pp) + self._max_y = len(pp[0]) + self._max_z = pp[0][0] + else: + self._max_x = 0 + self._max_y = 0 + self._max_z = 0 + else: + (self._max_x, self._max_y, self._max_z) = self.parent()._box def check(self): """ @@ -104,17 +128,25 @@ def check(self): EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.check() + sage: a = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: a.check() + sage: b = PlanePartition([[1,2],[1]]) + Traceback (most recent call last): + ... + ValueError: Not weakly decreasing along rows + sage: c = PlanePartition([[1,1],[2]]) + Traceback (most recent call last): + ... + ValueError: Not weakly decreasing along columns """ - if len(self) == 0: - return - if len(self) > self.parent()._box[0]: - raise ValueError("too big in z direction") - if len(self[0]) > self.parent()._box[1]: - raise ValueError("too big in y direction") - if self[0][0] > self.parent()._box[2]: - raise ValueError("too big in x direction") + for row in self: + if not all(c >= 0 for c in row): + raise ValueError("Entries not all nonnegative") + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + raise ValueError("Not weakly decreasing along rows") + for row, next in zip(self, self[1:]): + if not all(row[c] >= next[c] for c in range(len(next))): + raise ValueError("Not weakly decreasing along columns") def _repr_(self): """ @@ -201,6 +233,18 @@ def cells(self): L.append([r,c,h]) return L + def number_of_boxes(self): + r""" + Return the number of boxes in the plane partition. + + EXAMPLES:: + + sage: PP = PlanePartition([[3,1],[2]]) + sage: PP.number_of_boxes() + 6 + """ + return sum(sum(k for k in row) for row in self) + def _repr_diagram(self, show_box=False, use_unicode=False): r""" Return a string of the 3D diagram of ``self``. @@ -502,16 +546,61 @@ def add_rightside(i, j, k): TP += add_leftside(self.x_tableau()[r][c], r, c) TP.axes(show=False) return TP + + def contains(self, PP): + """ + + Return ``True`` if ``PP`` is a plane partition that fits + inside ``self``. + + Specifically, ``self`` contains ``PP`` if, for all `i`, `j`, + the height of ``PP`` at `ij` is less than or equal to the + height of ``self`` at `ij`. + + EXAMPLES:: + + sage: P1 = PlanePartition([[5,4,3],[3,2,2],[1]]) + sage: P2 = PlanePartition([[3,2],[1,1],[0,0],[0,0]]) + sage: P3 = PlanePartition([[5,5,5],[2,1,0]]) + sage: P1.contains(P2) + True + sage: P2.contains(P1) + False + sage: P1.contains(P3) + False + sage: P3.contains(P2) + True + """ + PP = PlanePartition(PP) + if len(self) < len(PP): + return False + + for i in range(len(PP)): + if len(self[i]) < len(PP[i]): + return False + + return all([self[i][j] >= PP[i][j] for j in range(len(PP[i])) for i in range(len(PP))]) + def complement(self, tableau_only=False): + # Complement needs to be more intelligent about which parent to return r""" Return the complement of ``self``. + If the parent of ``self`` consists only of partitions inside a given + box, then the complement is taken in this box. Otherwise, the + complement is taken in the smallest box containing the plane partition. + + If ``tableau_only`` is set to ``True``, then only the tableau + consisting of the projection of boxes size onto the xy-plane + is returned instead of a PlanePartition object. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.complement() - Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] + Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1]] sage: PP.complement(True) [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] """ @@ -532,11 +621,17 @@ def transpose(self, tableau_only=False): r""" Return the transpose of ``self``. + If ``tableau_only`` is set to ``True``, then only the tableau + consisting of the projection of boxes size onto the xy-plane + is returned instead of a PlanePartition object. This will + not necessarily have trailing rows or trailing zeros removed. + + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.transpose() - Plane partition [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] + Plane partition [[4, 2, 1], [3, 1, 1], [3, 1], [1]] sage: PP.transpose(True) [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] """ @@ -547,8 +642,14 @@ def transpose(self, tableau_only=False): T[c][r] = z_tab[r][c] if tableau_only: return T - else: + elif self.parent()._box == None or self.parent()._box[0] == self.parent()._box[1]: return type(self)(self.parent(), T, check=False) + new_box = (self.parent()._box[1],self.parent()._box[0],self.parent()._box[2]) + return PlanePartitions(new_box,symmetry=self.parent._symmetry) + # elif self._max_x != self._max_y: + # raise ValueError("Tranpose only supports parents with symmetric dimensions") + # else: + # return type(self)(self.parent(), T, check=False) def is_SPP(self): r""" @@ -633,6 +734,10 @@ def is_TSPP(self): def is_SCPP(self): r""" Return whether ``self`` is a self-complementary plane partition. + + + + EXAMPLES:: @@ -641,9 +746,12 @@ def is_SCPP(self): False sage: PP = PlanePartition([[4,4,4,4],[4,4,2,0],[4,2,0,0],[0,0,0,0]]) sage: PP.is_SCPP() + False + 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 """ - return self.z_tableau() == self.complement(True) + return self.z_tableau() == self.complement(tableau_only=True) def is_TCPP(self): r""" @@ -733,29 +841,257 @@ def is_TSSCPP(self): """ return self.is_TSPP() and self.is_SCPP() + def to_order_ideal(self): + """ + Return the order ideal corresponding to ``self``. + + TODO: As many families of symmetric plane partitions are in bijection + with order ideals in an associated poset, this function could + feasibly have options to send symmetric plane partitions + to the associated order ideal in that poset, instead. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] + sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] + """ + (a, b, c) = (self._max_x, self._max_y, self._max_z) + Q = posets.ProductOfChains([a,b,c]) + count = 0 + generate = [] + for i in range(len(self)): + for j in range(len(self[i])): + if (self[i][j] > 0): + generate.append((i,j,self[i][j]-1)) + count += 1 + oi = Q.order_ideal(generate) + return oi + + + + def maximal_boxes(self): + """ + Return the coordinates of the maximal boxes of ``self``. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes() + [[0, 2, 0], [1, 1, 1], [0, 0, 2], [2, 0, 1]] + sage: PlanePartition([[2,1],[1],[1]]).maximal_boxes() + [[0, 1, 0], [0, 0, 1], [2, 0, 0]] + """ + (a, b, c) = (self._max_x, self._max_y, self._max_z) + Q = posets.ProductOfChains([a,b,c]) + count = 0 + generate = [] + for i in range(len(self)): + for j in range(len(self[i])): + if (self[i][j] > 0): + generate.append((i,j,self[i][j]-1)) + count+=1 + oi = Q.order_ideal_generators(generate) + return [list(oi_elem) for oi_elem in oi] + + def cyclically_rotate(self, preserve_parent=False): + """ + Return the cyclic rotation of ``self``. + + By default, if the parent of ``self`` consists of plane + partitions inside an `a \times b \times c` box, the result + will have a parent consisting of partitions inside + a `c \times a \times b` box, unless the optional parameter + ``preserve_parents`` is set to ``True``. Enabling this setting + may give an element that is NOT an element of its parent. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).cyclically_rotate() + Plane partition [[3, 3, 1], [2, 2], [1]] + sage: PP = PlanePartition([[4,1],[1],[1]]) + sage: PP.cyclically_rotate() + Plane partition [[3, 1, 1, 1], [1]] + sage: PP == PP.cyclically_rotate().cyclically_rotate().cyclically_rotate() + True + sage: PP = PlanePartitions([4,3,2]).random_element() + sage: PP.cyclically_rotate().parent() + Plane partitions inside a 2 x 4 x 3 box + sage: PP = PlanePartitions([3,4,2])([[2,2,2,2],[2,2,2,2],[2,2,2,2]]) + sage: PP_rotated = PP.cyclically_rotate(preserve_parent=True) + sage: PP_rotated in PP_rotated.parent() + False + """ + (a, b, c) = (self._max_x, self._max_y, self._max_z) + new_antichain = [] + for elem in self.maximal_boxes(): + new = (elem[1], elem[2], elem[0]) + new_antichain.append(new) + ppMatrix = [[0] * (c) for i in range(b)] + for box in new_antichain: + y = box[0] + z = box[1] + x = box[2] + ppMatrix[y][z] = (x+1) + if new_antichain != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + # Start code for determining correct parent + if self.parent()._box == None or preserve_parent == True or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): + return type(self)(self.parent(), ppMatrix, check=False) + new_box = (self.parent()._box[2],self.parent()._box[0],self.parent()._box[1]) + return PlanePartitions(new_box,symmetry=self.parent()._symmetry)(ppMatrix) + #return PlanePartition(ppMatrix) + class PlanePartitions(UniqueRepresentation, Parent): r""" - All plane partitions inside a rectangular box of given side lengths. + A factory class for plane partitions. - INPUT: + PlanePartitions([a,b,c]) returns the class of plane partitions that fit + inside an a \times b \times c box. + + Optional keyword is 'symmetry'. + + Describe options. + + """ + @staticmethod + def __classcall_private__(cls, *args, **kwds): + r""" + This is a factory class which returns the appropriate parent based on + arguments. See the documentation for :class:`PlanePartitions` + for more information. + + TESTS:: + + sage: PlanePartitions() + Plane partitions + sage: PlanePartitions([3,3,3]) + Plane partitions inside a 3 x 3 x 3 box + sage: PlanePartitions(3) + 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 + """ + symmetry = kwds.get('symmetry', None) + if not args: + return PlanePartitions_all() + else: + box_size = None + if args: + # The first arg could be either a size or a box size + if isinstance(args[0], (int, Integer)): + return PlanePartitions_n(args[0]) + else: + box_size = args[0] + if symmetry == None: + return PlanePartitions_box(box_size) + elif symmetry == 'SPP': + return PlanePartitions_SPP(box_size) + elif symmetry == 'CSPP': + return PlanePartitions_CSPP(box_size) + elif symmetry == 'TSPP': + return PlanePartitions_TSPP(box_size) + elif symmetry == 'SCPP': + return PlanePartitions_SCPP(box_size) + elif symmetry == 'TCPP': + return PlanePartitions_TCPP(box_size) + elif symmetry == 'SSCPP': + return PlanePartitions_SSCPP(box_size) + elif symmetry == 'CSTCPP': + return PlanePartitions_CSTCPP(box_size) + elif symmetry == 'CSSCPP': + return PlanePartitions_CSSCPP(box_size) + elif symmetry == 'TSSCPP': + return PlanePartitions_TSSCPP(box_size) + else: + raise ValueError("invalid symmetry class option; must be None, 'SPP', 'CSPP', 'TSPP', 'SCPP', 'TCPP', 'SSCPP', 'CSTCPP', 'CSSCPP', or 'TSSCPP' ") + + + Element = PlanePartition + + + def __contains__(self, pp): + """ + Check to see that ``self`` is a valid plane partition. + + .. TODO: + + Figure out how redundant this is, given that the check function + exists for the factor class. Maybe only need __contains__ + on the fixed size and symmetry classes? + """ + for row in pp: + if not all(c >= 0 for c in row): + return False + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + return False + for row, next in zip(pp, pp[1:]): + if not all(row[c] >= next[c] for c in range(len(next))): + return False + return True + + + + + +class PlanePartitions_all(PlanePartitions): + r""" + All plane partitions. + + .. TODO: + + Consider giving this the structure of disjoint union of the classes + PlanePartitions(n) for n an integer. + """ - - ``box_size`` -- a triple of positive integers indicating the size - of the box containing the plane partition - EXAMPLES: + def __init__(self): + r""" + Initializes the class of all plane partitions. + + .. WARNING:: + + Input is not checked; please use :class:`PlanePartitions` to + ensure the options are properly parsed. + + TESTS:: + + sage: from sage.combinat.plane_partition import PlanePartitions_all + sage: P = PlanePartitions_all() + sage: TestSuite(P).run() # long time + """ + self._box = None + self._symmetry = None + super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) + + def __repr__(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: PlanePartitions() + Plane partitions + """ + return "Plane partitions" - This will create an instance to manipulate the plane partitions - in a `4 \times 3 \times 2` box:: - sage: P = PlanePartitions((4,3,2)) - sage: P - Plane partitions inside a 4 x 3 x 2 box - sage: P.cardinality() - 490 - .. SEEALSO:: - :class:`PlanePartition` +class PlanePartitions_box(PlanePartitions): + r""" + All plane partitions that fit inside a box of a specified size. """ @staticmethod def __classcall_private__(cls, box_size): @@ -769,23 +1105,23 @@ def __classcall_private__(cls, box_size): sage: P1 is P2 True """ - return super(PlanePartitions, cls).__classcall__(cls, tuple(box_size)) + return super(PlanePartitions_box, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): r""" - Initialize ``self`` + Initializes the class of plane partitions that fit in a box of a + specified size. EXAMPLES:: sage: PP = PlanePartitions((4,3,2)) sage: TestSuite(PP).run() """ - if len(box_size) != 3: - raise ValueError("invalid box size") + super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) self._box = box_size - Parent.__init__(self, category=FiniteEnumeratedSets()) + self._symmetry = None - def _repr_(self): + def __repr__(self): """ Return a string representation of ``self``. @@ -794,30 +1130,87 @@ def _repr_(self): sage: PlanePartitions((4,3,2)) Plane partitions inside a 4 x 3 x 2 box """ - return "Plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Plane partitions inside a %s x %s x %s box" % (self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def __contains__(self, x): + if len(x) == 0: + return True + return PlanePartitions.__contains__(self, x) and len(x) <= self._box[0] and len(x[0]) <= self._box[1] and x[0][0] <= self._box[2] + + def to_poset(self): + r""" + Returns the product of three chains poset, whose order ideals are + naturally in bijection with plane partitions inside a box. + """ + a=self._box[0] + b=self._box[1] + c=self._box[2] + return posets.ProductOfChains([a,b,c]) + + def from_order_ideal(self, I): + r""" + Return the plane partition corresponding to an order ideal in the + poset given in :meth:`to_poset`. + + Note: input may not be checked ? Optional check parameter if too much overhead? """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def from_antichain(self, A): + r""" + Return the plane partition corresponding to an antichain in the poset + given in :meth:`to_poset`. + + Note: input may not be checked? Optional parameter if too much overhead? + """ + a = self._box[0] + b = self._box[1] + c = self._box[2] + ppMatrix = [[0] * (b) for i in range(a)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + + #ac format ex: [x,y,z] + #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) + for ac in A: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[x][y] = (z+1) + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if A != []: + for i in range(a): + i = a-(i+1) + for j in range(b): + j = b-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < a-1: + iValue = ppMatrix[i+1][j] + if j < b-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + return self.element_class(self, ppMatrix) + + + def __iter__(self): + r""" Iterate over ``self``. EXAMPLES:: sage: list(PlanePartitions((1,2,1))) - [Plane partition [[0, 0]], - Plane partition [[1, 0]], - Plane partition [[1, 1]]] + [Plane partition [], Plane partition [[1, 1]], Plane partition [[1]]] """ - A = self._box[0] - B = self._box[1] - C = self._box[2] - from sage.combinat.tableau import SemistandardTableaux - for T in SemistandardTableaux([B for i in range(A)], max_entry=C+A): - PP = [[0 for i in range(B)] for j in range(A)] - for r in range(A): - for c in range(B): - PP[A-1-r][B-1-c] = T[r][c] - r - 1 - yield self.element_class(self, PP, check=False) + a = self._box[0] + b = self._box[1] + c = self._box[2] + pocp = posets.ProductOfChains([a,b,c]) + matrixList = [] #list of all PlanePartitions with parameters(a,b,c) + #iterate through each antichain of product of chains poset with parameters (a,b,c) + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + def cardinality(self): r""" @@ -846,8 +1239,8 @@ def cardinality(self): def box(self): """ - Return the sizes of the box of the plane partitions of ``self`` - are contained in. + Return the size of the box of the plane partition of ``self`` + is contained in. EXAMPLES:: @@ -870,19 +1263,1188 @@ def random_element(self): EXAMPLES:: sage: P = PlanePartitions((4,3,5)) - sage: p = P.random_element() - sage: p.parent() is P + sage: P.random_element() + Plane partition [[4, 3, 3], [4], [2]] + """ + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) + return self.element_class(self, Z, check=False) + + + +class PlanePartitions_n(PlanePartitions): + """ + Plane partitions with a fixed number of boxes. + """ + + def __init__(self, n): + r""" + Initializes the class of plane partitions with ``n`` boxes. + + .. WARNING:: + + Input is not checked; please use :class:`PlanePartitions` to + ensure the options are properly parsed. (CHECK: does this make sense?) + + TESTS:: + + sage: PP = PlanePartitions(4) + sage: type(PP) + + sage: TestSuite(PP).run() + """ + super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) + self._n = n +# self._box = (0,0,0) + self._box = None + self._symmetry = None + + def _repr_(self): + """ + TESTS:: + + sage: PlanePartitions(3) + Plane partitions of size 3 + """ + return "Plane partitions of size {}".format(self._n) + + def __contains__(self, x): + return PlanePartitions.__contains__(self, x) and x.number_of_boxes() == self._n + + def __iter__(self): + r""" + An iterator to generate all plane partitions of a fixed size. + + EXAMPLES:: + + sage: list(PlanePartitions(2)) + [Plane partition [[2]], Plane partition [[1, 1]], Plane partition [[1], [1]]] + """ + from sage.combinat.partition import Partitions + def PP_first_row_iter(n, la): + m = n-sum(la) + if m < 0: + yield + return + if m==0: + yield [la] + return + for k in range(m,0,-1): + for mu in P_in_shape_iter(k,la): + if mu is not None: + for PP in PP_first_row_iter(m, mu): + if PP is not None: + yield [la] + PP + + + def P_in_shape_iter(n, la): + if n<0 or sum(la)=n: + yield [n] + return + else: + yield + return + if sum(la)==n: + yield la + return + for mu_0 in range(min(n,la[0]),0,-1): + new_la = [min(mu_0,la[i]) for i in range(1,len(la))] + for mu in P_in_shape_iter(n-mu_0, new_la): + if mu is not None: + yield [mu_0]+mu + n = self._n + if n==0: + yield PlanePartition([]) + return + + for m in range(n,0,-1): + for la in Partitions(m): + for a in PP_first_row_iter(n,la): + yield self.element_class(self, a, check=False) + + def cardinality(self): + r""" + Return the number of plane partitions with ``n`` boxes. + + Calculated using the recurrence relation + + .. MATH: + + PL(n) = \sum_{k=1}^n PL(n-k)\sigma_2(k) + + where ``\sigma_k(n)`` is the sum of the kth powers of + divisors of n. + + """ + PPn = [1] + for i in range(1,1+self._n): + nextPPn = sum(PPn[i-k]*Sigma()(k,2) for k in range(1,i+1))/i + PPn.append(nextPPn) + return(Integer(PPn[-1])) + +#Symmetry classes are enumerated and labelled in order as in Proofs and +#Confirmations/Stanley (with all plane partitions being the first class) + + + + +#Class 2 + +class PlanePartitions_SPP(PlanePartitions): + +#How to handle when a!=b ? + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((3,3,2), symmetry='SPP') + sage: P2 = PlanePartitions([3,3,2], symmetry='SPP') + sage: P1 is P2 True """ - def leq(thing1, thing2): - return all(thing1[i] <= thing2[i] for i in range(len(thing1))) - elem = [(i,j,k) for i in range(self._box[0]) for j in range(self._box[1]) - for k in range(self._box[2])] - myposet = Poset((elem, leq)) - R = myposet.random_order_ideal() - Z = [[0 for i in range(self._box[1])] for j in range(self._box[0])] - for C in R: - Z[C[0]][C[1]] += 1 + return super(PlanePartitions_SPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: TestSuite(PP).run() + """ + super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'SPP' + + def _repr_(self): + return "Symmetric plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __contains__(self, x): + return PlanePartitions.__contains__(self, x) and x.is_SPP() + + + def to_poset(self): + r""" + Returns a poset whose order ideals are in bijection with + symmetric plane partitions. + """ + a=self._box[0] + b=self._box[1] + c=self._box[2] + pl = [] + cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) + for x in range(0,a): + for y in range(0,x+1): + for z in range(0,c): + pl.append((x,y,z)) + return Poset((pl,cmp)) + + def from_order_ideal(self, I): + r""" + Return the plane partition corresponding to an order ideal in the + poset given in :meth:`to_poset()`. + + Note: input may not be checked ? Optional check parameter if too much overhead? + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def from_antichain(self, A): + r""" + Return the plane partition corresponding to an antichain in the poset + given in :meth:`to_poset()`. + + Note: input may not be checked? Optional parameter if too much overhead? + """ + #Initialize an empty plane partition + a=self._box[0] + b=self._box[1] + c=self._box[2] + ppMatrix = [[0] * (b) for i in range(a)] + #Antichain indicates where the 'corners' will be in the + #plane partition + for ac in A: + x=ac[0] + y=ac[1] + z=ac[2] + ppMatrix[x][y] = (z+1) + #Fill out the rest of the plane partition using symmetry and the + #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) + if A!= []: + for i in range(a): + i = a-(i+1) + for j in range(b): + j = b-(j+1) + if (ppMatrix[i][j] == 0) and i>=j: + iValue = 0 + jValue = 0 + if i < a-1: + iValue = ppMatrix[i+1][j] + if j < b-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + elif j>i: + ppMatrix[i][j] = ppMatrix[j][i] + return self.element_class(self, ppMatrix) + + def __iter__(self): + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of symmetric plane partitions inside an `r \times r \times t` + box is equal to + + .. MATH:: + + \prod_{i=1}^{r} \frac{2*i + t - 1}{2*i - 1} * + \prod_{1 \leq i \leq j \leq r} \frac{i+j+t-1}{i+j-1} + + EXAMPLES:: + + sage: P = PlanePartitions((3,3,2), symmetry='SPP') + sage: P.cardinality() + 35 + """ + A = self._box[0] + B = self._box[1] + C = self._box[2] + leftProduct = (prod( (2*i + C - 1) / (2*i - 1) for i in range(1,A+1))) + rightProduct = (prod( (i + j + C - 1) / (i + j - 1) for j in range(1, A+1) for i in range(1, j) )) + return Integer(leftProduct * rightProduct) + + def random_element(self): + r""" + Return a uniformly random element of ``self``. + + ALGORITHM: + + This uses the + :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` + method and the natural bijection between symmetric plane partitions + and antichains in an associated poset. (FIX EXAMPLES) + + EXAMPLES:: + + sage: P = PlanePartitions((4,3,5)) + sage: P.random_element() + Plane partition [[4, 3, 3], [4], [2]] + """ + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) - Element = PlanePartition +#Class 3 + +class PlanePartitions_CSPP(PlanePartitions): + +#For some reason works if not(a == b == c) + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2), symmetry='CSPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='CSPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: TestSuite(PP).run() + """ + super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'CSPP' + + def _repr_(self): + return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def to_poset(self): + """ + MAKE SURE DOC EXPLICITLY DESCRIBES WHAT FUNDAMENTAL DOMAIN LOOKS LIKE + """ + a=self._box[0] + b=self._box[1] + c=self._box[2] + cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) + cmp2 = lambda x,y : cmp(x,y) or cmp(x,(y[2],y[0],y[1])) or cmp(x,(y[1],y[2],y[0])) + pl = [] + for x in range(0,a): + for y in range(0, b): + for z in range(x,c): + if y <= z and (x != z or y == x): + pl.append((x,y,z)) + return Poset((pl, cmp2)) + + def from_antichain(self, acl): + a=self._box[0] + b=self._box[1] + c=self._box[2] + ppMatrix = [[0] * (c) for i in range(b)] + #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + #ac format ex: [x,y,z] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + ppMatrix[y][z] = (x+1) + ppMatrix[z][x] = (y+1) + ppMatrix[x][y] = (z+1) + + + #for each value in current antichain, fill in the rest of the + #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is + #now in plane partition format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + return self.element_class(self, ppMatrix) + + def from_order_ideal(self, I): + r""" + Return the plane partition corresponding to an order ideal in the + poset given in :meth:`to_poset`. + + Note: input may not be checked ? Optional check parameter if too much overhead? + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def __iter__(self): + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of cyclically symmetric plane partitions inside an + `r \times r \times r` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{r} \frac{3i - 1}{3i - 2}\right) + \left(\prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{2i+j-1}\right) + + EXAMPLES:: + + sage: P = PlanePartitions((4,4,4), symmetry='CSPP') + sage: P.cardinality() + 132 + """ + A = self._box[0] + B = self._box[1] + C = self._box[2] + 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) + + +# Class 4 + + +class PlanePartitions_TSPP(PlanePartitions): +# Totally symmetric plane partitions + +# Make sure inputs checked, code doesn't have a,b,c treated properly + + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2), symmetry='TSPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='TSPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: TestSuite(PP).run() + """ + super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'TSPP' + + def _repr_(self): + return "Totally symmetric plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def to_poset(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] + cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) + pl = [] + for x in range(0,a): + for y in range(x, b): + for z in range(y,c): + pl.append((x,y,z)) + return Poset((pl,cmp)) + + def from_antichain(self, acl): + a=self._box[0] + b=self._box[1] + c=self._box[2] + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + + + ppMatrix[y][z] = (x+1) #x,y,z + ppMatrix[z][x] = (y+1) #y,z,x + ppMatrix[x][y] = (z+1) #z,x,y + + ppMatrix[z][y] = (x+1) #x,z,y + ppMatrix[x][z] = (y+1) #y,x,z + ppMatrix[y][x] = (z+1) #z,y,x + + + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + if acl != []: + for i in range(b): + i = b-(i+1) + for j in range(c): + j = c-(j+1) + if (ppMatrix[i][j] == 0): + iValue = 0 + jValue = 0 + if i < b-1: + iValue = ppMatrix[i+1][j] + if j < c-1: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + return self.element_class(self, ppMatrix) + + def random_element(self): + return self.to_poset().from_antichain(self.to_poset().random_antichain()) + + def __iter__(self): + for A in self.to_poset().antichains_iterator(): + yield self.from_antichain(A) + + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of totally symmetric plane partitions inside an + `r \times r \times r` box is equal to + + .. MATH:: + + \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{i+2j-2} + + EXAMPLES:: + + sage: P = PlanePartitions((4,4,4), symmetry='TSPP') + sage: P.cardinality() + 66 + """ + A = self._box[0] + B = self._box[1] + C = self._box[2] + 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) )) + + + +# Class 5 + +class PlanePartitions_SCPP(PlanePartitions): +# Self-complementary plane partitions + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2), symmetry='SCPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='SCPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') + sage: TestSuite(PP).run() + """ +# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): +# raise ValueError("box sides cannot all be odd") + super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'SCPP' + + def _repr_(self): + return "Self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] + def Partitions_inside_lambda(la): + "Returns the list of partitions contained in la with the same number of parts including 0s." + if len(la)==0: + yield [] + return + LIST = [] + 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 for i in la] + return + + def Partitions_inside_lambda_with_smallest_at_least_k(la,k): + "Returns the list of partitions contained in la with the smallest entry at least k" + if len(la)==0: + yield [] + return + if la[-1] < k: + yield + return + LIST = [] + for mu in Partitions_inside_lambda([la[i]-k for i in range(len(la))]): + yield ([mu[i]+k for i in range(len(la))]) + return + + def possible_middle_row_for_b_odd(a,c): + "Returns the list of possible middle row for SCPP inside box(a,b,c) when b is odd" + if a*c % 2 == 1: + yield + return + LIST = [] + for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor(a/2))]): + nu = [c-mu[len(mu)-1-i] for i in range(len(mu))] + if a % 2 ==0: + la = nu + mu + else: + la = nu + [c/2] + mu + yield (la) + return + + def possible_middle_row_for_b_even(a,c): + "Returns the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" + LIST = [] + for mu in Partitions_inside_lambda([floor(c/2) for i in range((a+1)/2)]): + nu = [c-mu[len(mu)-1-i] for i in range(floor(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): + "Returns PPs with first row la and with k rows in total" + if k == 0: + yield [] + return + if k == 1: + yield [la] + return + LIST = [] + 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): + "Returns the complement of PP with respect to height c" + if len(PP) == 0: + return [] + b = len(PP) + a = len(PP[0]) + return [[c-PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] + + if a*b*c % 2 == 1: + return + + if b % 2 == 1: + for la in possible_middle_row_for_b_odd(a,c): # la is the middle row of SCPP + 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 + 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): + r""" + Return the cardinality of ``self``. + + The number of self complementary plane partitions inside a + `2a \times 2b \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{r}\prod_{j=1}^{b} \frac{i + j + c - 1}{i + j - 1}\right)^2 + + + + The number of self complementary plane partitions inside an + `(2a+1) \times 2b \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + + + The number of self complementary plane partitions inside an + `(2a+1) \times (2b+1) \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a}\prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right) + + EXAMPLES:: + + sage: P = PlanePartitions((4,4,4), symmetry='SCPP') + sage: P.cardinality() + 400 + + sage: P = PlanePartitions((5,4,4), symmetry='SCPP') + sage: P.cardinality() + 1000 + + sage: P = PlanePartitions((5,5,4), symmetry='SCPP') + sage: P.cardinality() + 2500 + """ + r=self._box[0] + s=self._box[1] + t=self._box[2] + if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) + if r % 2 == 1 and s % 2 == 0 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+t/2)))) + if r % 2 == 0 and s % 2 == 1 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) + if r % 2 == 0 and s % 2 == 0 and t % 2 == 1: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) + if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) + if r % 2 == 1 and s % 2 == 0 and t % 2 == 1: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) + if r % 2 == 0 and s % 2 == 1 and t % 2 == 1: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+(t-1)/2+1)))) + if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: + return Integer(0) + + +#Class 6 + +class PlanePartitions_TCPP(PlanePartitions): + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,3,2), symmetry='TCPP') + sage: P2 = PlanePartitions([4,3,2], symmetry='TCPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_TCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TCPP') + sage: TestSuite(PP).run() + """ +# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): +# raise ValueError("box sides cannot all be odd") + super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'TCPP' + + def _repr_(self): + return "Transpose complement plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_TCPP(): + yield self.element_class(self,p) + return + + + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + The number of transpose complement plane partitions inside an + `a \times a \times 2b` box is equal to + + .. MATH:: + + \binom{b+1-1}{a-1}\prod_{1\leq i\leq j a-2} \frac{i + j + 2b - 1}{i + j - 1} + """ + + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a==b and c % 2 == 0: + 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))) + else: + return Integer(0) + +#Class 7 + +class PlanePartitions_SSCPP(PlanePartitions): + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,4,2), symmetry='SSCPP') + sage: P2 = PlanePartitions([4,4,2], symmetry='SSCPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_SSCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') + sage: TestSuite(PP).run() + """ + +#Think about how to check a=b and not all a,b,c odd + + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("box sides cannot all be odd") + super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'SSCPP' + + def _repr_(self): + return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_SSCPP(): + yield self.element_class(self,p) + return + + def cardinality(self): + r=self._box[0] + s=self._box[1] + t=self._box[2] + if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+r/2) for k in range(1,1+t/2)))) + if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+(r-1)/2) for j in range(1,1+((r-1)/2)+1) for k in range(1,1+t/2)))) + return Integer(0) + +#Class 8 + +class PlanePartitions_CSTCPP(PlanePartitions): +#Cyclically symmetric transpose complement partitions + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((3,3,3), symmetry='CSTCPP') + sage: P2 = PlanePartitions([3,3,3], symmetry='CSTCPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSTCPP') + sage: TestSuite(PP).run() + """ + super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'CSTCPP' + + def _repr_(self): + return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_CSTCPP(): + yield self.element_class(self,p) + return + + def cardinality(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a == b and b == c and a % 2 == 0: + return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range(1+(a/2)-1))) + return Integer(0) + +# Class 9 + + +class PlanePartitions_CSSCPP(PlanePartitions): +# Cyclically symmetric self-complementary plane partitions + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((3,3,3), symmetry='CSSCPP') + sage: P2 = PlanePartitions([3,3,3], symmetry='CSSCPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSSCPP') + sage: TestSuite(PP).run() + """ + super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'CSSCPP' + + def _repr_(self): + return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self): + for p in PlanePartitions(self._box): + if p.is_CSSCPP(): + yield self.element_class(self,) + return + + def cardinality(self): + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a == b and b == c and a % 2 == 0: + return Integer(prod( ((factorial(3*i+1)**2/(factorial(a+i)**2) for i in range((a/2)))))) + return Integer(0) + + + +#Class 10 + +class PlanePartitions_TSSCPP(PlanePartitions): +#Totally symmetric self-complementary plane partitions + @staticmethod + def __classcall_private__(cls, box_size): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: P1 = PlanePartitions((4,4,4), symmetry='TSSCPP') + sage: P2 = PlanePartitions([4,4,4], symmetry='TSSCPP') + sage: P1 is P2 + True + """ + return super(PlanePartitions_TSSCPP, cls).__classcall__(cls, tuple(box_size)) + + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([4,4,4], symmetry='TSSCPP') + sage: TestSuite(PP).run() + """ + if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): + raise ValueError("invalid box size; must be (2r,2r,2r)") + super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) + self._box = box_size + self._symmetry = 'TSSCPP' + + def _repr_(self): + return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def to_poset(self): + cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) + def componentwise_comparer(thing1,thing2): + if len(thing1) == len(thing2): + if all(thing1[i] <= thing2[i] for i in range(len(thing1))): + return True + return False + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a != b or b != c or a != c: + return + + pl = [] + for x in range(0,a/2 - 2 + 1): + for y in range(x, a/2 - 2 + 1): + for z in range(0,a/2 - 2 + 1): + if z <= a/2 - 2 - y: + pl.append((x,y,z)) + + return Poset((pl,cmp)) + + def from_antichain(self, acl): + #ac format ex: [x,y,z] + a=self._box[0] + b=self._box[1] + c=self._box[2] + n=a + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + width = n/2 - 1 + height = n/2 - 1 + + #generate inner triagle + for i in range(width): + for j in range(height): + if(i <= j): + for ac in acl: + if ac[0] == i and ac[1] == j: + zVal = ac[2] + matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] + if zVal + 1 > matrixVal: + ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 + + #fill back + for i in range(width): + i = width-(i+1) + i = i + n/2 + for j in range(height): + j = height-(j+1) + j = j + n/2 + if (ppMatrix[i][j] == 0): + if i >= j: + iValue = 0 + jValue = 0 + if i < n: + iValue = ppMatrix[i+1][j] + if j < n: + jValue = ppMatrix[i][j+1] + ppMatrix[i][j] = max(iValue,jValue) + + + #fill half of triangle symmetrically + for i in range(width): + i = i + n/2 + for j in range(height): + j = j + n/2 + if i >= j: + ppMatrix[j][i] = ppMatrix[i][j] + + #upper left box + for i in range(n/2): + for j in range(n/2): + ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] + + + #fill in lower left cube with values n/2 + for i in range(n/2): + for j in range(n/2): + x = i + y = j + if(ppMatrix[x][y+(n/2)]) == 0: + ppMatrix[x][y+(n/2)] = n/2 + if(ppMatrix[x+(n/2)][y]) == 0: + ppMatrix[x+(n/2)][y] = n/2 + + + #add and subtract values from lower left cube to be rotation of lower right cube + for i in range(n/2): + for j in range(n/2): + x = i+(n/2) + y = j+(n/2) + if ppMatrix[x][y] > 0: + z = ppMatrix[x][y] + for cVal in range(z): + #build onto lower left cube + ppMatrix[x][0+cVal] += 1 + #carve out of lower left cube + ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 + + #fill in upper right cube symmetrically with lower left + for i in range(n/2): + for j in range(n/2): + ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] + return self.element_class(self, ppMatrix) + + + + + + def __iter__(self): +# def componentwise_comparer(thing1,thing2): +# if len(thing1) == len(thing2): +# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): +# return True +# return False +# a=self._box[0] +# b=self._box[1] +# c=self._box[2] +# n = a +# b = n +# c = n + +# pl = [] +# for x in range(0,n/2 - 2 + 1): +# for y in range(x, n/2 - 2 + 1): +# for z in range(0,n/2 - 2 + 1): +# if z <= n/2 - 2 - y: +# pl.append((x,y,z)) + +# pocp = Poset((pl,componentwise_comparer)) +# cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) +# pocp = Poset((pl,cmp)) + +# matrixList = [] #list of all PlaneParitions with parameters(a,b,c) + #iterate through each antichain of product of chains poset with paramaters (a,b,c) + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + return +# #ac format ex: [x,y,z] +# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] +# width = n/2 - 1 +# height = n/2 - 1 + +# #generate inner triagle +# for i in range(width): +# for j in range(height): +# if(i <= j): +# for ac in acl: +# if ac[0] == i and ac[1] == j: +# zVal = ac[2] +# matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] +# if zVal + 1 > matrixVal: +# ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 + +# #fill back +# for i in range(width): +# i = width-(i+1) +# i = i + n/2 +# for j in range(height): +# j = height-(j+1) +# j = j + n/2 +# if (ppMatrix[i][j] == 0): +# if i >= j: +# iValue = 0 +# jValue = 0 +# if i < n: +# iValue = ppMatrix[i+1][j] +# if j < n: +# jValue = ppMatrix[i][j+1] +# ppMatrix[i][j] = max(iValue,jValue) + + +# #fill half of triangle symmetrically +# for i in range(width): +# i = i + n/2 +# for j in range(height): +# j = j + n/2 +# if i >= j: +# ppMatrix[j][i] = ppMatrix[i][j] + +# #upper left box +# for i in range(n/2): +# for j in range(n/2): +# ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] + + +# #fill in lower left cube with values n/2 +# for i in range(n/2): +# for j in range(n/2): +# x = i +# y = j +# if(ppMatrix[x][y+(n/2)]) == 0: +# ppMatrix[x][y+(n/2)] = n/2 +# if(ppMatrix[x+(n/2)][y]) == 0: +# ppMatrix[x+(n/2)][y] = n/2 + + +# #add and subtract values from lower left cube to be rotation of lower right cube +# for i in range(n/2): +# for j in range(n/2): +# x = i+(n/2) +# y = j+(n/2) +# if ppMatrix[x][y] > 0: +# z = ppMatrix[x][y] +# for cVal in range(z): +# #build onto lower left cube +# ppMatrix[x][0+cVal] += 1 +# #carve out of lower left cube +# ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 + +# #fill in upper right cube symmetrically with lower left +# for i in range(n/2): +# for j in range(n/2): +# ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] +# yield self.element_class(self, ppMatrix) + + From 1ea27f9dda37680c21b0a1e074369f25478a9145 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 20 Oct 2020 17:17:19 -0500 Subject: [PATCH 37/74] Hopefully cleaned up merge conflict --- src/sage/combinat/plane_partition.py | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 62c4b340e04..74d89bd486e 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -40,28 +40,28 @@ from sage.functions.other import floor, ceil, binomial, factorial -class PlanePartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): - r""" - A plane partition. - - A *plane partition* is a stack of cubes in the positive orthant. +#class PlanePartition(ClonableList, +# metaclass=InheritComparisonClasscallMetaclass): +# r""" +# A plane partition. - INPUT: +# A *plane partition* is a stack of cubes in the positive orthant. - - ``PP`` -- a list of lists which represents a tableau +# INPUT: - - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, - where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, - `y`-axis, `z`-axis, respectively; if this is not given, it is - determined by the smallest box bounding ``PP`` +# - ``PP`` -- a list of lists which represents a tableau - OUTPUT: +# - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, +# where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, +# `y`-axis, `z`-axis, respectively; if this is not given, it is +# determined by the smallest box bounding ``PP`` - The plane partition whose tableau representation is ``PP``. +# OUTPUT: +# The plane partition whose tableau representation is ``PP``. +# """ -@add_metaclass(InheritComparisonClasscallMetaclass) +#@add_metaclass(InheritComparisonClasscallMetaclass) class PlanePartition(ClonableList): @staticmethod def __classcall_private__(cls, PP): From d56b64a47c846e38e1240080f2af48d7c33ad532 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 24 Aug 2021 16:32:05 -0500 Subject: [PATCH 38/74] Added typings for new methods --- src/sage/combinat/plane_partition.py | 107 ++++++++++++++------------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 0fb76d54260..bf477262fe3 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -186,7 +186,7 @@ def to_tableau(self) -> Tableau: """ return Tableau(self) - def z_tableau(self): + def z_tableau(self) -> Tableau: r""" Return the projection of ``self`` in the `z` direction. @@ -201,7 +201,7 @@ def z_tableau(self): Z[C[0]][C[1]] += 1 return Z - def y_tableau(self): + def y_tableau(self) -> Tableau: r""" Return the projection of ``self`` in the `y` direction. @@ -216,7 +216,7 @@ def y_tableau(self): Y[C[2]][C[0]] += 1 return Y - def x_tableau(self): + def x_tableau(self) -> Tableau: r""" Return the projection of ``self`` in the `x` direction. @@ -248,7 +248,7 @@ def cells(self) -> list: L.append([r, c, h]) return L - def number_of_boxes(self): + def number_of_boxes(self) -> Integer: r""" Return the number of boxes in the plane partition. @@ -260,7 +260,7 @@ def number_of_boxes(self): """ return sum(sum(k for k in row) for row in self) - def _repr_diagram(self, show_box=False, use_unicode=False): + def _repr_diagram(self, show_box=False, use_unicode=False) -> str: r""" Return a string of the 3D diagram of ``self``. @@ -571,7 +571,7 @@ def add_rightside(i, j, k): TP.axes(show=False) return TP - def contains(self, PP): + def contains(self, PP) -> bool: """ Return ``True`` if ``PP`` is a plane partition that fits @@ -606,7 +606,7 @@ def contains(self, PP): return all([self[i][j] >= PP[i][j] for j in range(len(PP[i])) for i in range(len(PP))]) - def complement(self, tableau_only=False): + def complement(self, tableau_only=False) -> PP: # Complement needs to be more intelligent about which parent to return r""" Return the complement of ``self``. @@ -641,7 +641,7 @@ def complement(self, tableau_only=False): else: return type(self)(self.parent(), T, check=False) - def transpose(self, tableau_only=False): + def transpose(self, tableau_only=False) -> PP: r""" Return the transpose of ``self``. @@ -893,7 +893,7 @@ def to_order_ideal(self): - def maximal_boxes(self): + def maximal_boxes(self) -> list: """ Return the coordinates of the maximal boxes of ``self``. @@ -916,7 +916,7 @@ def maximal_boxes(self): oi = Q.order_ideal_generators(generate) return [list(oi_elem) for oi_elem in oi] - def cyclically_rotate(self, preserve_parent=False): + def cyclically_rotate(self, preserve_parent=False) -> PP: """ Return the cyclic rotation of ``self``. @@ -1097,7 +1097,7 @@ def __init__(self): self._symmetry = None super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) - def __repr__(self): + def _repr_(self) -> str: """ Return a string representation of ``self``. @@ -1172,7 +1172,7 @@ def to_poset(self): c=self._box[2] return posets.ProductOfChains([a,b,c]) - def from_order_ideal(self, I): + def from_order_ideal(self, I) -> PP: r""" Return the plane partition corresponding to an order ideal in the poset given in :meth:`to_poset`. @@ -1181,7 +1181,7 @@ def from_order_ideal(self, I): """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) - def from_antichain(self, A): + def from_antichain(self, A) -> PP: r""" Return the plane partition corresponding to an antichain in the poset given in :meth:`to_poset`. @@ -1337,7 +1337,7 @@ def __init__(self, n): self._box = None self._symmetry = None - def _repr_(self): + def _repr_(self) -> str: """ TESTS:: @@ -1346,10 +1346,10 @@ def _repr_(self): """ return "Plane partitions of size {}".format(self._n) - def __contains__(self, x): + def __contains__(self, x) -> bool: return PlanePartitions.__contains__(self, x) and x.number_of_boxes() == self._n - def __iter__(self): + def __iter__(self) -> Iterator: r""" An iterator to generate all plane partitions of a fixed size. @@ -1407,7 +1407,7 @@ def P_in_shape_iter(n, la): for a in PP_first_row_iter(n,la): yield self.element_class(self, a, check=False) - def cardinality(self): + def cardinality(self) -> Integer: r""" Return the number of plane partitions with ``n`` boxes. @@ -1464,11 +1464,11 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'SPP' - def _repr_(self): + def _repr_(self) -> str: return "Symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __contains__(self, x): + def __contains__(self, x) -> bool: return PlanePartitions.__contains__(self, x) and x.is_SPP() @@ -1488,7 +1488,7 @@ def to_poset(self): pl.append((x,y,z)) return Poset((pl,cmp)) - def from_order_ideal(self, I): + def from_order_ideal(self, I) -> PP: r""" Return the plane partition corresponding to an order ideal in the poset given in :meth:`to_poset()`. @@ -1497,7 +1497,7 @@ def from_order_ideal(self, I): """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) - def from_antichain(self, A): + def from_antichain(self, A) -> PP: r""" Return the plane partition corresponding to an antichain in the poset given in :meth:`to_poset()`. @@ -1535,11 +1535,11 @@ def from_antichain(self, A): ppMatrix[i][j] = ppMatrix[j][i] return self.element_class(self, ppMatrix) - def __iter__(self): + def __iter__(self) -> Iterator: for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) - def cardinality(self): + def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -1564,7 +1564,7 @@ def cardinality(self): rightProduct = (prod( (i + j + C - 1) / (i + j - 1) for j in range(1, A+1) for i in range(1, j) )) return Integer(leftProduct * rightProduct) - def random_element(self): + def random_element(self) -> PP: r""" Return a uniformly random element of ``self``. @@ -1615,7 +1615,7 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'CSPP' - def _repr_(self): + def _repr_(self) -> str: return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1670,7 +1670,7 @@ def from_antichain(self, acl): ppMatrix[i][j] = max(iValue,jValue) return self.element_class(self, ppMatrix) - def from_order_ideal(self, I): + def from_order_ideal(self, I) -> PP: r""" Return the plane partition corresponding to an order ideal in the poset given in :meth:`to_poset`. @@ -1679,11 +1679,11 @@ def from_order_ideal(self, I): """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) - def __iter__(self): + def __iter__(self) -> Iterator: for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) - def cardinality(self): + def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -1742,11 +1742,14 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'TSPP' - def _repr_(self): + def _repr_(self) -> str: return "Totally symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) def to_poset(self): + """ + MAKE SURE DOC EXPLICITLY DESCRIBES WHAT FUNDAMENTAL DOMAIN LOOKS LIKE + """ a=self._box[0] b=self._box[1] c=self._box[2] @@ -1758,7 +1761,7 @@ def to_poset(self): pl.append((x,y,z)) return Poset((pl,cmp)) - def from_antichain(self, acl): + def from_antichain(self, acl) -> PP: a=self._box[0] b=self._box[1] c=self._box[2] @@ -1794,15 +1797,15 @@ def from_antichain(self, acl): ppMatrix[i][j] = max(iValue,jValue) return self.element_class(self, ppMatrix) - def random_element(self): + def random_element(self) -> PP: return self.to_poset().from_antichain(self.to_poset().random_antichain()) - def __iter__(self): + def __iter__(self) -> Iterator: for A in self.to_poset().antichains_iterator(): yield self.from_antichain(A) - def cardinality(self): + def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -1857,11 +1860,11 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'SCPP' - def _repr_(self): + def _repr_(self) -> str: return "Self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def __iter__(self) -> Iterator: a=self._box[0] b=self._box[1] c=self._box[2] @@ -1958,7 +1961,7 @@ def complement(PP,c): yield self.element_class(self, PP_above+PP_below) return - def cardinality(self): + def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -2053,11 +2056,11 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'TCPP' - def _repr_(self): + def _repr_(self) -> str: return "Transpose complement plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def __iter__(self) -> Iterator: for p in PlanePartitions(self._box): if p.is_TCPP(): yield self.element_class(self,p) @@ -2065,7 +2068,7 @@ def __iter__(self): - def cardinality(self): + def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -2118,17 +2121,17 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'SSCPP' - def _repr_(self): + def _repr_(self) -> str: return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def __iter__(self) -> Iterator: for p in PlanePartitions(self._box): if p.is_SSCPP(): yield self.element_class(self,p) return - def cardinality(self): + def cardinality(self) -> Integer: r=self._box[0] s=self._box[1] t=self._box[2] @@ -2167,17 +2170,17 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'CSTCPP' - def _repr_(self): + def _repr_(self) -> str: return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def __iter__(self) -> Iterator: for p in PlanePartitions(self._box): if p.is_CSTCPP(): yield self.element_class(self,p) return - def cardinality(self): + def cardinality(self) -> Integer: a=self._box[0] b=self._box[1] c=self._box[2] @@ -2215,17 +2218,17 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'CSSCPP' - def _repr_(self): + def _repr_(self) -> str: return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self): + def __iter__(self) -> Iterator: for p in PlanePartitions(self._box): if p.is_CSSCPP(): yield self.element_class(self,) return - def cardinality(self): + def cardinality(self) -> Integer: a=self._box[0] b=self._box[1] c=self._box[2] @@ -2266,7 +2269,7 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'TSSCPP' - def _repr_(self): + def _repr_(self) -> str: return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -2292,7 +2295,7 @@ def componentwise_comparer(thing1,thing2): return Poset((pl,cmp)) - def from_antichain(self, acl): + def from_antichain(self, acl) -> PP: #ac format ex: [x,y,z] a=self._box[0] b=self._box[1] @@ -2302,7 +2305,7 @@ def from_antichain(self, acl): width = n/2 - 1 height = n/2 - 1 - #generate inner triagle + #generate inner triangle for i in range(width): for j in range(height): if(i <= j): @@ -2379,7 +2382,7 @@ def from_antichain(self, acl): - def __iter__(self): + def __iter__(self) -> Iterator: # def componentwise_comparer(thing1,thing2): # if len(thing1) == len(thing2): # if all(thing1[i] <= thing2[i] for i in range(len(thing1))): From 5f9650c78ef90445e87ff1b885d18439fe852882 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 24 Aug 2021 17:12:40 -0500 Subject: [PATCH 39/74] Added docstrings for new iterators. --- src/sage/combinat/plane_partition.py | 100 ++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index bf477262fe3..67bf652646f 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -24,7 +24,7 @@ # **************************************************************************** from typing import NewType, Iterator, Tuple -from sage.structure.list_clone import ClonableList +from sage.structure.list_clone import ClonableList, ClonableArray from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent @@ -1536,6 +1536,17 @@ def from_antichain(self, A) -> PP: return self.element_class(self, ppMatrix) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((2,2,1), symmetry='SPP')) + [Plane partition [], + Plane partition [[1, 1], [1, 1]], + Plane partition [[1, 1], [1]], + Plane partition [[1]]] + """ for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) @@ -1680,6 +1691,18 @@ def from_order_ideal(self, I) -> PP: return self.from_antichain(self.to_poset().order_ideal_generators(I)) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((2,2,2), symmetry='CSPP')) + [Plane partition [], + Plane partition [[2, 2], [2, 2]], + Plane partition [[2, 2], [2, 1]], + Plane partition [[2, 1], [1]], + Plane partition [[1]]] + """ for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) @@ -1801,6 +1824,18 @@ def random_element(self) -> PP: return self.to_poset().from_antichain(self.to_poset().random_antichain()) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((4,3,2), symmetry='TSPP')) + [Plane partition [], + Plane partition [[2, 2], [2, 2]], + Plane partition [[2, 2], [2, 1]], + Plane partition [[2, 1], [1]], + Plane partition [[1]]] + """ for A in self.to_poset().antichains_iterator(): yield self.from_antichain(A) @@ -1865,6 +1900,18 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((4,3,2), symmetry='SCPP')) + [Plane partition [], + Plane partition [[2, 2], [2, 2]], + Plane partition [[2, 2], [2, 1]], + Plane partition [[2, 1], [1]], + Plane partition [[1]]] + """ a=self._box[0] b=self._box[1] c=self._box[2] @@ -2061,6 +2108,18 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((3,3,2), symmetry='TCPP')) + [Plane partition [[2, 2, 1], [2, 1], [1]], + Plane partition [[2, 1, 1], [2, 1, 1], [1]], + Plane partition [[2, 2, 1], [1, 1], [1, 1]], + Plane partition [[2, 1, 1], [1, 1, 1], [1, 1]], + Plane partition [[1, 1, 1], [1, 1, 1], [1, 1, 1]]] + """ for p in PlanePartitions(self._box): if p.is_TCPP(): yield self.element_class(self,p) @@ -2126,6 +2185,16 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((3,3,2), symmetry='SSCPP')) + [Plane partition [[2, 2, 1], [2, 1], [1]], + Plane partition [[2, 1, 1], [1, 1, 1], [1, 1]], + Plane partition [[1, 1, 1], [1, 1, 1], [1, 1, 1]]] + """ for p in PlanePartitions(self._box): if p.is_SSCPP(): yield self.element_class(self,p) @@ -2163,7 +2232,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry='CSTCPP') + sage: PP = PlanePartitions([2,2,2], symmetry='CSTCPP') sage: TestSuite(PP).run() """ super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) @@ -2175,6 +2244,14 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((2,2,2), symmetry='CSTCPP')) + [Plane partition [[2, 1], [1]]] + """ for p in PlanePartitions(self._box): if p.is_CSTCPP(): yield self.element_class(self,p) @@ -2223,9 +2300,17 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: list(PlanePartitions((2,2,2), symmetry='CSSCPP')) + [Plane partition [[2, 1], [1]]] + """ for p in PlanePartitions(self._box): if p.is_CSSCPP(): - yield self.element_class(self,) + yield self.element_class(self,p) return def cardinality(self) -> Integer: @@ -2383,6 +2468,15 @@ def from_antichain(self, acl) -> PP: def __iter__(self) -> Iterator: + """ + Iterate over ``self``. + + EXAMPLES:: + + 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]]] + """ # def componentwise_comparer(thing1,thing2): # if len(thing1) == len(thing2): # if all(thing1[i] <= thing2[i] for i in range(len(thing1))): From f0c59c48294f5eb9cb4e75d3b32b197b74c5a086 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 25 Aug 2021 13:00:18 -0500 Subject: [PATCH 40/74] Fixed issue with metaclass making constructor not work. Changed the parent complement method returns when no bounding box specified. --- src/sage/combinat/plane_partition.py | 53 +++++++++++++++------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 67bf652646f..08d014d9b72 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -44,40 +44,40 @@ PP = NewType('PP', 'PlanePartition') -class PlanePartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): - r""" - A plane partition. +#class PlanePartition(ClonableArray, +# metaclass=InheritComparisonClasscallMetaclass): +# r""" +# A plane partition. - A *plane partition* is a stack of cubes in the positive orthant. +# A *plane partition* is a stack of cubes in the positive orthant. - INPUT: +# INPUT: - - ``PP`` -- a list of lists which represents a tableau +# - ``PP`` -- a list of lists which represents a tableau - - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, - where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, - `y`-axis, `z`-axis, respectively; if this is not given, it is - determined by the smallest box bounding ``PP`` +# - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, +# where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, +# `y`-axis, `z`-axis, respectively; if this is not given, it is +# determined by the smallest box bounding ``PP`` - OUTPUT: +# OUTPUT: - The plane partition whose tableau representation is ``PP``. +# The plane partition whose tableau representation is ``PP``. - EXAMPLES:: +# EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP - Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] +# sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) +# sage: PP +# Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] - TESTS:: +# TESTS:: - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: TestSuite(PP).run() - """ +# sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) +# sage: TestSuite(PP).run() +# """ #@add_metaclass(InheritComparisonClasscallMetaclass) -class PlanePartition(ClonableList): +class PlanePartition(ClonableList, metaclass=InheritComparisonClasscallMetaclass): @staticmethod def __classcall_private__(cls, PP): """ @@ -122,8 +122,7 @@ def __init__(self, parent, pp, check=True): while pp[i] and not pp[i][-1]: del pp[i][-1] if not pp[i]: - pp.pop(i) - + pp.pop(i) ClonableList.__init__(self, parent, pp, check=check) if self.parent()._box is None: if pp: @@ -614,6 +613,7 @@ def complement(self, tableau_only=False) -> PP: If the parent of ``self`` consists only of partitions inside a given box, then the complement is taken in this box. Otherwise, the complement is taken in the smallest box containing the plane partition. + The empty plane partition with no box specified is its own complement. If ``tableau_only`` is set to ``True``, then only the tableau consisting of the projection of boxes size onto the xy-plane @@ -638,7 +638,10 @@ def complement(self, tableau_only=False) -> PP: T[A - 1 - r][B - 1 - c] = C - z_tab[r][c] if tableau_only: return T - else: + elif not self.parent()._box: + pp = PlanePartitions() + return pp.element_class(pp, T) + else: return type(self)(self.parent(), T, check=False) def transpose(self, tableau_only=False) -> PP: From 2266c9f716bea34884052a41adbfbfe31316d44b Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 25 Aug 2021 13:29:27 -0500 Subject: [PATCH 41/74] Added ValueError for bad dimension input to symmetry classes --- src/sage/combinat/plane_partition.py | 37 +++++++++++++++++++--------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 08d014d9b72..20772b0da51 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -6,6 +6,7 @@ - Jang Soo Kim (2016): Initial implementation - Jessica Striker (2016): Added additional methods +- Kevin Dilks (2021): Added symmetry classes """ # **************************************************************************** # Copyright (C) 2016 Jang Soo Kim , @@ -1463,6 +1464,8 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,2], symmetry='SPP') sage: TestSuite(PP).run() """ + if box_size[0] != box_size[1]: + raise ValueError("x and y dimensions must match") super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SPP' @@ -1611,8 +1614,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2), symmetry='CSPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='CSPP') + sage: P1 = PlanePartitions((4,4,4), symmetry='CSPP') + sage: P2 = PlanePartitions([4,4,4], symmetry='CSPP') sage: P1 is P2 True """ @@ -1625,6 +1628,8 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') sage: TestSuite(PP).run() """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions must match") super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSPP' @@ -1750,8 +1755,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2), symmetry='TSPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='TSPP') + sage: P1 = PlanePartitions((4,4,4), symmetry='TSPP') + sage: P2 = PlanePartitions([4,4,4], symmetry='TSPP') sage: P1 is P2 True """ @@ -1764,6 +1769,8 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') sage: TestSuite(PP).run() """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions must match") super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TSPP' @@ -1892,8 +1899,8 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') sage: TestSuite(PP).run() """ -# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): -# raise ValueError("box sides cannot all be odd") + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("box sides cannot all be odd") super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SCPP' @@ -2100,8 +2107,8 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry='TCPP') sage: TestSuite(PP).run() """ -# if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): -# raise ValueError("box sides cannot all be odd") + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("x, y, and z dimensions cannot all be odd") super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TCPP' @@ -2153,6 +2160,7 @@ def cardinality(self) -> Integer: #Class 7 class PlanePartitions_SSCPP(PlanePartitions): +#Symmetric self-complementary plane partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -2175,10 +2183,11 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ -#Think about how to check a=b and not all a,b,c odd + if box_size[0]!=box_size[1]: + raise ValueError("x and y dimensions must be equal") if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("box sides cannot all be odd") + raise ValueError("x, y, and z dimensions cannot all be odd") super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SSCPP' @@ -2238,6 +2247,8 @@ def __init__(self, box_size): sage: PP = PlanePartitions([2,2,2], symmetry='CSTCPP') sage: TestSuite(PP).run() """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions must match") super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSTCPP' @@ -2294,6 +2305,10 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry='CSSCPP') sage: TestSuite(PP).run() """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions must match") + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("x, y, and z dimensions cannot all be odd") super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSSCPP' @@ -2352,7 +2367,7 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): - raise ValueError("invalid box size; must be (2r,2r,2r)") + raise ValueError("x, y, and z dimensions must be (2r,2r,2r)") super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TSSCPP' From 5b8d6495a86e1b3e04e727f69cdc8de60a670aed Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 25 Aug 2021 13:36:48 -0500 Subject: [PATCH 42/74] Removed artifacts from SCPP iterator building a list instead of being an iterator --- src/sage/combinat/plane_partition.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 20772b0da51..d045a49823e 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1930,7 +1930,6 @@ def Partitions_inside_lambda(la): if len(la)==0: yield [] return - LIST = [] 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): @@ -1946,7 +1945,7 @@ def Partitions_inside_lambda_with_smallest_at_least_k(la,k): if la[-1] < k: yield return - LIST = [] + for mu in Partitions_inside_lambda([la[i]-k for i in range(len(la))]): yield ([mu[i]+k for i in range(len(la))]) return @@ -1956,7 +1955,6 @@ def possible_middle_row_for_b_odd(a,c): if a*c % 2 == 1: yield return - LIST = [] for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor(a/2))]): nu = [c-mu[len(mu)-1-i] for i in range(len(mu))] if a % 2 ==0: @@ -1968,7 +1966,6 @@ def possible_middle_row_for_b_odd(a,c): def possible_middle_row_for_b_even(a,c): "Returns the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" - LIST = [] for mu in Partitions_inside_lambda([floor(c/2) for i in range((a+1)/2)]): nu = [c-mu[len(mu)-1-i] for i in range(floor(a/2))] for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu,mu[0]): @@ -1986,7 +1983,6 @@ def PPs_with_first_row_la_and_with_k_rows(la,k): if k == 1: yield [la] return - LIST = [] 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) From 62067aff10fe0dda721654b0e62a0023c8d0b5e8 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 25 Aug 2021 13:46:36 -0500 Subject: [PATCH 43/74] Added floor in SCPP iterator for when first dimension is even --- src/sage/combinat/plane_partition.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index d045a49823e..4f49035d9fa 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1915,7 +1915,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((4,3,2), symmetry='SCPP')) + sage: list(PlanePartitions((2,2,2), symmetry='SCPP')) [Plane partition [], Plane partition [[2, 2], [2, 2]], Plane partition [[2, 2], [2, 1]], @@ -1966,7 +1966,8 @@ def possible_middle_row_for_b_odd(a,c): def possible_middle_row_for_b_even(a,c): "Returns the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" - for mu in Partitions_inside_lambda([floor(c/2) for i in range((a+1)/2)]): +# for mu in Partitions_inside_lambda([floor(c/2) for i in range((a+1)/2)]): + for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor((a+1)/2))]): nu = [c-mu[len(mu)-1-i] for i in range(floor(a/2))] for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu,mu[0]): la = tau + mu From ff1eacf86d5c66da0ba65ea19b9f14423fded9c6 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 25 Aug 2021 15:29:31 -0500 Subject: [PATCH 44/74] Made xyz tableau methods output a Tableau object by default --- src/sage/combinat/plane_partition.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 4f49035d9fa..a569bf39606 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -186,10 +186,15 @@ def to_tableau(self) -> Tableau: """ return Tableau(self) - def z_tableau(self) -> Tableau: + def z_tableau(self, tableau=True) -> Tableau: r""" Return the projection of ``self`` in the `z` direction. + If ``tableau`` is set to ``False``, then only the list of lists + consisting of the projection of boxes size onto the xy-plane + is returned instead of a Tableau object. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -199,12 +204,19 @@ def z_tableau(self) -> Tableau: Z = [[0 for i in range(self._max_y)] for j in range(self._max_x)] for C in self.cells(): Z[C[0]][C[1]] += 1 + if tableau: + return Tableau(Z) return Z - def y_tableau(self) -> Tableau: + def y_tableau(self, tableau=True) -> Tableau: r""" Return the projection of ``self`` in the `y` direction. + If ``tableau`` is set to ``False``, then only the list of lists + consisting of the projection of boxes size onto the xz-plane + is returned instead of a Tableau object. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -214,12 +226,19 @@ def y_tableau(self) -> Tableau: Y = [[0 for i in range(self._max_x)] for j in range(self._max_z)] for C in self.cells(): Y[C[2]][C[0]] += 1 + if tableau: + return Tableau(Y) return Y - def x_tableau(self) -> Tableau: + def x_tableau(self, tableau=True) -> Tableau: r""" Return the projection of ``self`` in the `x` direction. + If ``tableau`` is set to ``False``, then only the list of lists + consisting of the projection of boxes size onto the yz-plane + is returned instead of a Tableau object. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -229,6 +248,8 @@ def x_tableau(self) -> Tableau: X = [[0 for i in range(self._max_z)] for j in range(self._max_y)] for C in self.cells(): X[C[1]][C[2]] += 1 + if tableau: + return Tableau(X) return X def cells(self) -> list: From 237f05fa57368ff6acf7ca93f90ea828d488dc2d Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 25 Aug 2021 16:12:43 -0500 Subject: [PATCH 45/74] Cleaned up some doctests with bad input, fixed error in CSSCPP cardinality method --- src/sage/combinat/plane_partition.py | 97 ++++++++++++++-------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index a569bf39606..528427de0c3 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -798,7 +798,7 @@ def is_SCPP(self) -> bool: sage: PP.is_SCPP() True """ - return self.z_tableau() == self.complement(tableau_only=True) + return self.z_tableau(tableau=False) == self.complement(tableau_only=True) def is_TCPP(self) -> bool: r""" @@ -888,33 +888,33 @@ def is_TSSCPP(self) -> bool: """ return self.is_TSPP() and self.is_SCPP() - def to_order_ideal(self): - """ - Return the order ideal corresponding to ``self``. - - TODO: As many families of symmetric plane partitions are in bijection - with order ideals in an associated poset, this function could - feasibly have options to send symmetric plane partitions - to the associated order ideal in that poset, instead. - - EXAMPLES:: - - sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() - [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] - sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() - [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] - """ - (a, b, c) = (self._max_x, self._max_y, self._max_z) - Q = posets.ProductOfChains([a,b,c]) - count = 0 - generate = [] - for i in range(len(self)): - for j in range(len(self[i])): - if (self[i][j] > 0): - generate.append((i,j,self[i][j]-1)) - count += 1 - oi = Q.order_ideal(generate) - return oi +# def to_order_ideal(self): +# """ +# Return the order ideal corresponding to ``self``. + +# TODO: As many families of symmetric plane partitions are in bijection +# with order ideals in an associated poset, this function could +# feasibly have options to send symmetric plane partitions +# to the associated order ideal in that poset, instead. +# +# EXAMPLES:: +# +# sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() +# [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] +# sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() +# [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] +# """ +# (a, b, c) = (self._max_x, self._max_y, self._max_z) +# Q = posets.ProductOfChains([a,b,c]) +# count = 0 +# generate = [] +# for i in range(len(self)): +# for j in range(len(self[i])): +# if (self[i][j] > 0): +# generate.append((i,j,self[i][j]-1)) +# count += 1 +# oi = Q.order_ideal(generate) +# return oi @@ -924,10 +924,10 @@ def maximal_boxes(self) -> list: EXAMPLES:: - sage: PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes() - [[0, 2, 0], [1, 1, 1], [0, 0, 2], [2, 0, 1]] - sage: PlanePartition([[2,1],[1],[1]]).maximal_boxes() - [[0, 1, 0], [0, 0, 1], [2, 0, 0]] + sage: sorted(PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes()) + [[0, 0, 2], [0, 2, 0], [1, 1, 1], [2, 0, 1]] + sage: sorted(PlanePartition([[2,1],[1],[1]]).maximal_boxes()) + [[0, 0, 1], [0, 1, 0], [2, 0, 0]] """ (a, b, c) = (self._max_x, self._max_y, self._max_z) Q = posets.ProductOfChains([a,b,c]) @@ -1626,7 +1626,6 @@ def random_element(self) -> PP: class PlanePartitions_CSPP(PlanePartitions): -#For some reason works if not(a == b == c) @staticmethod def __classcall_private__(cls, box_size): @@ -1681,7 +1680,7 @@ def from_antichain(self, acl): b=self._box[1] c=self._box[2] ppMatrix = [[0] * (c) for i in range(b)] - #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] #ac format ex: [x,y,z] for ac in acl: x = ac[0] @@ -1860,12 +1859,12 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((4,3,2), symmetry='TSPP')) + sage: list(PlanePartitions((2,2,2), symmetry='TSPP')) [Plane partition [], - Plane partition [[2, 2], [2, 2]], - Plane partition [[2, 2], [2, 1]], - Plane partition [[2, 1], [1]], - Plane partition [[1]]] + Plane partition [[2, 2], [2, 2]], + Plane partition [[2, 2], [2, 1]], + Plane partition [[2, 1], [1]], + Plane partition [[1]]] """ for A in self.to_poset().antichains_iterator(): yield self.from_antichain(A) @@ -1937,11 +1936,10 @@ def __iter__(self) -> Iterator: EXAMPLES:: sage: list(PlanePartitions((2,2,2), symmetry='SCPP')) - [Plane partition [], - Plane partition [[2, 2], [2, 2]], - Plane partition [[2, 2], [2, 1]], + [Plane partition [[1, 1], [1, 1]], + Plane partition [[2], [2]], Plane partition [[2, 1], [1]], - Plane partition [[1]]] + Plane partition [[2, 2]]] """ a=self._box[0] b=self._box[1] @@ -2122,7 +2120,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry='TCPP') + sage: PP = PlanePartitions([4,3,2], symmetry='TCPP') sage: TestSuite(PP).run() """ if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): @@ -2309,8 +2307,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((3,3,3), symmetry='CSSCPP') - sage: P2 = PlanePartitions([3,3,3], symmetry='CSSCPP') + sage: P1 = PlanePartitions((4,4,4), symmetry='CSSCPP') + sage: P2 = PlanePartitions([4,4,4], symmetry='CSSCPP') sage: P1 is P2 True """ @@ -2320,7 +2318,7 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([3,3,3], symmetry='CSSCPP') + sage: PP = PlanePartitions([2,2,2], symmetry='CSSCPP') sage: TestSuite(PP).run() """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: @@ -2354,7 +2352,10 @@ def cardinality(self) -> Integer: b=self._box[1] c=self._box[2] if a == b and b == c and a % 2 == 0: - return Integer(prod( ((factorial(3*i+1)**2/(factorial(a+i)**2) for i in range((a/2)))))) + return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) +# numerator = prod(factorial(3*i+1)**2 for i in range(a/2)) +# denominator = prod(factorial(a/2+i)**2 for i in range(a/2)) +# return(Integer(numerator / denominator)) return Integer(0) From e36726f9479ad6381c0ff33768e86b12d172d8e8 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 25 Aug 2021 16:32:31 -0500 Subject: [PATCH 46/74] Cleaned out some previous concerns/notes to self --- src/sage/combinat/plane_partition.py | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 528427de0c3..98deaa85dcd 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1202,7 +1202,6 @@ def from_order_ideal(self, I) -> PP: Return the plane partition corresponding to an order ideal in the poset given in :meth:`to_poset`. - Note: input may not be checked ? Optional check parameter if too much overhead? """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) @@ -1211,7 +1210,6 @@ def from_antichain(self, A) -> PP: Return the plane partition corresponding to an antichain in the poset given in :meth:`to_poset`. - Note: input may not be checked? Optional parameter if too much overhead? """ a = self._box[0] b = self._box[1] @@ -1226,7 +1224,7 @@ def from_antichain(self, A) -> PP: z = ac[2] ppMatrix[x][y] = (z+1) - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format if A != []: for i in range(a): i = a-(i+1) @@ -1264,14 +1262,6 @@ def __iter__(self) -> Iterator: PP[A - 1 - r][B - 1 - c] = T[r][c] - r - 1 yield self.element_class(self, PP, check=False) -# a = self._box[0] -# b = self._box[1] -# c = self._box[2] -# pocp = posets.ProductOfChains([a,b,c]) -# matrixList = [] #list of all PlanePartitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with parameters (a,b,c) -# for acl in self.to_poset().antichains_iterator(): -# yield self.from_antichain(acl) @@ -1519,8 +1509,6 @@ def from_order_ideal(self, I) -> PP: r""" Return the plane partition corresponding to an order ideal in the poset given in :meth:`to_poset()`. - - Note: input may not be checked ? Optional check parameter if too much overhead? """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) @@ -1528,8 +1516,6 @@ def from_antichain(self, A) -> PP: r""" Return the plane partition corresponding to an antichain in the poset given in :meth:`to_poset()`. - - Note: input may not be checked? Optional parameter if too much overhead? """ #Initialize an empty plane partition a=self._box[0] @@ -1713,8 +1699,6 @@ def from_order_ideal(self, I) -> PP: r""" Return the plane partition corresponding to an order ideal in the poset given in :meth:`to_poset`. - - Note: input may not be checked ? Optional check parameter if too much overhead? """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) @@ -2353,9 +2337,6 @@ def cardinality(self) -> Integer: c=self._box[2] if a == b and b == c and a % 2 == 0: return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) -# numerator = prod(factorial(3*i+1)**2 for i in range(a/2)) -# denominator = prod(factorial(a/2+i)**2 for i in range(a/2)) -# return(Integer(numerator / denominator)) return Integer(0) From 61e5797d0ff9bac8ae49c55e6d9a0807efb01bc4 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 26 Aug 2021 11:15:09 -0500 Subject: [PATCH 47/74] Added _repr_ doctest and cleaned up valid input tests --- src/sage/combinat/plane_partition.py | 128 ++++++++++++++++++++------- 1 file changed, 96 insertions(+), 32 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 98deaa85dcd..ba841f9c562 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -628,7 +628,6 @@ def contains(self, PP) -> bool: def complement(self, tableau_only=False) -> PP: - # Complement needs to be more intelligent about which parent to return r""" Return the complement of ``self``. @@ -1070,13 +1069,17 @@ def __classcall_private__(cls, *args, **kwds): def __contains__(self, pp): """ - Check to see that ``self`` is a valid plane partition. + Check to see that ``pp`` is a valid plane partition. + + EXAMPLES:: + + sage: [[3,2,1],[2,1]] in PlanePartitions() + True + sage: [[3,2,1],[1,2]] in PlanePartitions() + False + sage: [[3,2,1],[3,3]] in PlanePartitions() + False - .. TODO: - - Figure out how redundant this is, given that the check function - exists for the factor class. Maybe only need __contains__ - on the fixed size and symmetry classes? """ for row in pp: if not all(c >= 0 for c in row): @@ -1243,12 +1246,12 @@ def from_antichain(self, A) -> PP: def __iter__(self) -> Iterator: r""" - Iterate over ``self``. + An iterator for all partitions that fit inside a box. EXAMPLES:: sage: list(PlanePartitions((1,2,1))) - [Plane partition [], Plane partition [[1, 1]], Plane partition [[1]]] + [Plane partition [], Plane partition [[1]], Plane partition [[1, 1]]] """ A = self._box[0] @@ -1306,7 +1309,7 @@ def box(self) -> Tuple: def random_element(self) -> PP: r""" - Return a uniformly random element of ``self``. + Return a uniformly random plane partition inside a box. ALGORITHM: @@ -1348,13 +1351,12 @@ def __init__(self, n): """ super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) self._n = n -# self._box = (0,0,0) self._box = None self._symmetry = None def _repr_(self) -> str: """ - TESTS:: + EXAMPLES:: sage: PlanePartitions(3) Plane partitions of size 3 @@ -1452,7 +1454,6 @@ def cardinality(self) -> Integer: class PlanePartitions_SPP(PlanePartitions): -#How to handle when a!=b ? @staticmethod def __classcall_private__(cls, box_size): @@ -1482,6 +1483,12 @@ def __init__(self, box_size): self._symmetry = 'SPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,2], symmetry='SPP') + Symmetric plane partitions inside a 3 x 3 x 2 box + """ return "Symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1641,6 +1648,12 @@ def __init__(self, box_size): self._symmetry = 'CSPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,3], symmetry='CSPP') + Cyclically symmetric plane partitions inside a 3 x 3 x 3 box + """ return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1780,6 +1793,12 @@ def __init__(self, box_size): self._symmetry = 'TSPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,3], symmetry='TSPP') + Totally symmetric plane partitions inside a 3 x 3 x 3 box + """ return "Totally symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1904,12 +1923,18 @@ def __init__(self, box_size): sage: TestSuite(PP).run() """ if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("box sides cannot all be odd") + raise ValueError("dimensions cannot all be odd") super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SCPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4,3,2], symmetry='SCPP') + Self-complementary plane partitions inside a 4 x 3 x 2 box + """ return "Self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -2093,8 +2118,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2), symmetry='TCPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='TCPP') + sage: P1 = PlanePartitions((3,3,2), symmetry='TCPP') + sage: P2 = PlanePartitions([3,3,2], symmetry='TCPP') sage: P1 is P2 True """ @@ -2104,16 +2129,24 @@ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([4,3,2], symmetry='TCPP') + sage: PP = PlanePartitions([3,3,2], symmetry='TCPP') sage: TestSuite(PP).run() """ - if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("x, y, and z dimensions cannot all be odd") + if (box_size[2] % 2 == 1): + raise ValueError("z dimension must be even") + if box_size[0] != box_size[1]: + raise ValueError("x and y dimensions must be equal") super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TCPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,2], symmetry='TCPP') + Transpose complement plane partitions inside a 3 x 3 x 2 box + """ return "Transpose complement plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -2186,13 +2219,19 @@ def __init__(self, box_size): if box_size[0]!=box_size[1]: raise ValueError("x and y dimensions must be equal") - if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("x, y, and z dimensions cannot all be odd") + if (box_size[0] % 2 == 1 or box_size[1] % 2 == 1 or box_size[2] % 2 == 1): + raise ValueError("all dimensions must be even") super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SSCPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4,4,2], symmetry='SSCPP') + Symmetric self-complementary plane partitions inside a 4 x 4 x 2 box + """ return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -2202,10 +2241,13 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((3,3,2), symmetry='SSCPP')) - [Plane partition [[2, 2, 1], [2, 1], [1]], - Plane partition [[2, 1, 1], [1, 1, 1], [1, 1]], - Plane partition [[1, 1, 1], [1, 1, 1], [1, 1, 1]]] + sage: list(PlanePartitions((4,4,2), symmetry='SSCPP')) + [Plane partition [[2, 2, 2, 1], [2, 2, 1], [2, 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, 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]]] """ for p in PlanePartitions(self._box): if p.is_SSCPP(): @@ -2233,8 +2275,8 @@ def __classcall_private__(cls, box_size): EXAMPLES:: - sage: P1 = PlanePartitions((3,3,3), symmetry='CSTCPP') - sage: P2 = PlanePartitions([3,3,3], symmetry='CSTCPP') + sage: P1 = PlanePartitions((2,2,2), symmetry='CSTCPP') + sage: P2 = PlanePartitions([2,2,2], symmetry='CSTCPP') sage: P1 is P2 True """ @@ -2249,12 +2291,20 @@ def __init__(self, box_size): """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: raise ValueError("x, y, and z dimensions must match") + if box_size[0] % 2 == 1: + raise ValueError("all dimensions must be even") super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSTCPP' def _repr_(self) -> str: - return "Cyclically symmetric transpose complement partitions inside a {} x {} x {} box".format( + """ + EXAMPLES:: + + sage: PlanePartitions([4,4,4], symmetry='CSTCPP') + Cyclically symmetric transpose complement plane partitions inside a 4 x 4 x 4 box + """ + return "Cyclically symmetric transpose complement plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: @@ -2307,13 +2357,19 @@ def __init__(self, box_size): """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: raise ValueError("x, y, and z dimensions must match") - if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("x, y, and z dimensions cannot all be odd") + if box_size[0] % 2 == 1: + raise ValueError("all dimensions must be even") super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSSCPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4,4,4], symmetry='CSSCPP') + Cyclically symmetric self-complementary plane partitions inside a 4 x 4 x 4 box + """ return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -2366,13 +2422,21 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,4,4], symmetry='TSSCPP') sage: TestSuite(PP).run() """ - if (box_size[0] != box_size[1] or (box_size[1] != box_size[2]) or box_size[0] % 2 != 0): - raise ValueError("x, y, and z dimensions must be (2r,2r,2r)") + if (box_size[0] != box_size[1]) or (box_size[1] != box_size[2]): + raise ValueError("all dimensions must be equal") + if box_size[0] % 2 != 0: + raise ValueError("all dimensions must be even") super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TSSCPP' def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4,4,4], symmetry='TSSCPP') + Totally symmetric self-complementary plane partitions inside a 4 x 4 x 4 box + """ return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) From c43655d4b2d1e25af47dae8723c8b02c86418953 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 26 Aug 2021 11:38:28 -0500 Subject: [PATCH 48/74] Cleaned up iterator doc --- src/sage/combinat/plane_partition.py | 132 ++++----------------------- 1 file changed, 18 insertions(+), 114 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index ba841f9c562..f4f4f970b3e 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1192,7 +1192,7 @@ def __contains__(self, x): def to_poset(self): r""" - Returns the product of three chains poset, whose order ideals are + Return the product of three chains poset, whose order ideals are naturally in bijection with plane partitions inside a box. """ a=self._box[0] @@ -1557,7 +1557,7 @@ def from_antichain(self, A) -> PP: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for symmetric plane partitions. EXAMPLES:: @@ -1717,7 +1717,7 @@ def from_order_ideal(self, I) -> PP: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for cyclically symmetric plane partitions. EXAMPLES:: @@ -1858,7 +1858,7 @@ def random_element(self) -> PP: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for totally symmetric plane partitions. EXAMPLES:: @@ -1940,7 +1940,7 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for self-complementary plane partitions. EXAMPLES:: @@ -2152,7 +2152,7 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for transpose complement plane partitions. EXAMPLES:: @@ -2237,7 +2237,7 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for symmetric self-complementary plane partitions. EXAMPLES:: @@ -2259,9 +2259,15 @@ def cardinality(self) -> Integer: s=self._box[1] t=self._box[2] if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+r/2) for k in range(1,1+t/2)))) + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) + for i in range(1,1+r/2) + for j in range(1,1+r/2) + for k in range(1,1+t/2)))) if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+(r-1)/2) for j in range(1,1+((r-1)/2)+1) for k in range(1,1+t/2)))) + return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) + for i in range(1,1+(r-1)/2) + for j in range(1,1+((r-1)/2)+1) + for k in range(1,1+t/2)))) return Integer(0) #Class 8 @@ -2309,7 +2315,7 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for cyclically symmetry transpose complement plane partitions. EXAMPLES:: @@ -2375,7 +2381,7 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for cyclically symmetric self-complementary plane partitions. EXAMPLES:: @@ -2551,7 +2557,7 @@ def from_antichain(self, acl) -> PP: def __iter__(self) -> Iterator: """ - Iterate over ``self``. + An iterator for totally symmetric self-complementary plane partitions. EXAMPLES:: @@ -2559,110 +2565,8 @@ def __iter__(self) -> Iterator: [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]]] """ -# def componentwise_comparer(thing1,thing2): -# if len(thing1) == len(thing2): -# if all(thing1[i] <= thing2[i] for i in range(len(thing1))): -# return True -# return False -# a=self._box[0] -# b=self._box[1] -# c=self._box[2] -# n = a -# b = n -# c = n - -# pl = [] -# for x in range(0,n/2 - 2 + 1): -# for y in range(x, n/2 - 2 + 1): -# for z in range(0,n/2 - 2 + 1): -# if z <= n/2 - 2 - y: -# pl.append((x,y,z)) - -# pocp = Poset((pl,componentwise_comparer)) -# cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) -# pocp = Poset((pl,cmp)) - -# matrixList = [] #list of all PlaneParitions with parameters(a,b,c) - #iterate through each antichain of product of chains poset with paramaters (a,b,c) for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) return -# #ac format ex: [x,y,z] -# ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] -# width = n/2 - 1 -# height = n/2 - 1 - -# #generate inner triagle -# for i in range(width): -# for j in range(height): -# if(i <= j): -# for ac in acl: -# if ac[0] == i and ac[1] == j: -# zVal = ac[2] -# matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] -# if zVal + 1 > matrixVal: -# ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 - -# #fill back -# for i in range(width): -# i = width-(i+1) -# i = i + n/2 -# for j in range(height): -# j = height-(j+1) -# j = j + n/2 -# if (ppMatrix[i][j] == 0): -# if i >= j: -# iValue = 0 -# jValue = 0 -# if i < n: -# iValue = ppMatrix[i+1][j] -# if j < n: -# jValue = ppMatrix[i][j+1] -# ppMatrix[i][j] = max(iValue,jValue) - - -# #fill half of triangle symmetrically -# for i in range(width): -# i = i + n/2 -# for j in range(height): -# j = j + n/2 -# if i >= j: -# ppMatrix[j][i] = ppMatrix[i][j] - -# #upper left box -# for i in range(n/2): -# for j in range(n/2): -# ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] - - -# #fill in lower left cube with values n/2 -# for i in range(n/2): -# for j in range(n/2): -# x = i -# y = j -# if(ppMatrix[x][y+(n/2)]) == 0: -# ppMatrix[x][y+(n/2)] = n/2 -# if(ppMatrix[x+(n/2)][y]) == 0: -# ppMatrix[x+(n/2)][y] = n/2 - - -# #add and subtract values from lower left cube to be rotation of lower right cube -# for i in range(n/2): -# for j in range(n/2): -# x = i+(n/2) -# y = j+(n/2) -# if ppMatrix[x][y] > 0: -# z = ppMatrix[x][y] -# for cVal in range(z): -# #build onto lower left cube -# ppMatrix[x][0+cVal] += 1 -# #carve out of lower left cube -# ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 - -# #fill in upper right cube symmetrically with lower left -# for i in range(n/2): -# for j in range(n/2): -# ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] -# yield self.element_class(self, ppMatrix) From a2bb515ab47ec7d406f8d44dc333ffbe24edb816 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 27 Aug 2021 11:43:21 -0500 Subject: [PATCH 49/74] Continuing documentation cleanup, added a few missing methods --- src/sage/combinat/plane_partition.py | 360 +++++++++++++++++++++++---- 1 file changed, 318 insertions(+), 42 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index f4f4f970b3e..e57bbcaf3c0 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1178,7 +1178,7 @@ def _repr_(self) -> str: EXAMPLES:: - sage: PlanePartitions((4,3,2)) + sage: PlanePartitions([4,3,2]) Plane partitions inside a 4 x 3 x 2 box """ @@ -1194,6 +1194,11 @@ def to_poset(self): r""" Return the product of three chains poset, whose order ideals are naturally in bijection with plane partitions inside a box. + + EXAMPLES:: + + sage: PlanePartitions([2,2,2]).to_poset() + Finite lattice containing 8 elements """ a=self._box[0] b=self._box[1] @@ -1205,6 +1210,11 @@ def from_order_ideal(self, I) -> PP: Return the plane partition corresponding to an order ideal in the poset given in :meth:`to_poset`. + EXAMPLES:: + + sage: I = [(1, 0, 0), (1, 0, 1), (1, 1, 0), (0, 1, 0), (0, 0, 0), (0, 0, 1), (0, 1, 1)] + sage: PlanePartitions([2,2,2]).from_order_ideal(I) + Plane partition [[2, 2], [2, 1]] """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) @@ -1213,6 +1223,11 @@ def from_antichain(self, A) -> PP: Return the plane partition corresponding to an antichain in the poset given in :meth:`to_poset`. + EXAMPLES:: + + sage: A = [(1,0,1), (0,1,1), (1,1,0)] + sage: PlanePartitions([2,2,2]).from_antichain(A) + Plane partition [[2, 2], [2, 1]] """ a = self._box[0] b = self._box[1] @@ -1475,9 +1490,13 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,2], symmetry='SPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='SPP') + Traceback (most recent call last): + ... + ValueError: x and y dimensions (4 and 3) must be equal """ if box_size[0] != box_size[1]: - raise ValueError("x and y dimensions must match") + raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SPP' @@ -1500,6 +1519,14 @@ def to_poset(self): r""" Returns a poset whose order ideals are in bijection with symmetric plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: PP.to_poset() + Finite poset containing 12 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True """ a=self._box[0] b=self._box[1] @@ -1514,15 +1541,29 @@ def to_poset(self): def from_order_ideal(self, I) -> PP: r""" - Return the plane partition corresponding to an order ideal in the - poset given in :meth:`to_poset()`. + Return the symmetric plane partition corresponding to an order ideal + in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: I = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (2, 0, 0)] + sage: PP.from_order_ideal(I) + Plane partition [[1, 1, 1], [1, 1], [1]] """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) def from_antichain(self, A) -> PP: r""" - Return the plane partition corresponding to an antichain in the poset - given in :meth:`to_poset()`. + Return the symmetric plane partition corresponding to an antichain + in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: A = [(2, 2, 0), (1, 0, 1), (1, 1, 0)] + sage: PP.from_antichain(A) + Plane partition [[2, 2, 1], [2, 1, 1], [1, 1, 1]] """ #Initialize an empty plane partition a=self._box[0] @@ -1592,7 +1633,9 @@ def cardinality(self) -> Integer: B = self._box[1] C = self._box[2] leftProduct = (prod( (2*i + C - 1) / (2*i - 1) for i in range(1,A+1))) - rightProduct = (prod( (i + j + C - 1) / (i + j - 1) for j in range(1, A+1) for i in range(1, j) )) + rightProduct = (prod( (i + j + C - 1) / (i + j - 1) + for j in range(1, A+1) + for i in range(1, j) )) return Integer(leftProduct * rightProduct) def random_element(self) -> PP: @@ -1604,13 +1647,13 @@ def random_element(self) -> PP: This uses the :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` method and the natural bijection between symmetric plane partitions - and antichains in an associated poset. (FIX EXAMPLES) + and order ideals in an associated poset. EXAMPLES:: - sage: P = PlanePartitions((4,3,5)) - sage: P.random_element() - Plane partition [[4, 3, 3], [4], [2]] + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: PP.random_element() + Plane partition [[2, 2, 2], [2, 2], [2]] """ Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) @@ -1640,9 +1683,13 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='CSPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions must match") + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSPP' @@ -1659,7 +1706,16 @@ def _repr_(self) -> str: def to_poset(self): """ - MAKE SURE DOC EXPLICITLY DESCRIBES WHAT FUNDAMENTAL DOMAIN LOOKS LIKE + Return a partially ordered set whose order ideals are in bijection with + cyclically symmetric plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: PP.to_poset() + Finite poset containing 11 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True """ a=self._box[0] b=self._box[1] @@ -1674,12 +1730,24 @@ def to_poset(self): pl.append((x,y,z)) return Poset((pl, cmp2)) - def from_antichain(self, acl): + def from_antichain(self, acl) -> PP: + r""" + Return the cyclically symmetric plane partition corresponding to an + antichain in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: A = [(0, 2, 2), (1, 1, 1)] + sage: PP.from_antichain(A) + Plane partition [[3, 3, 3], [3, 2, 1], [3, 1, 1]] + """ a=self._box[0] b=self._box[1] c=self._box[2] ppMatrix = [[0] * (c) for i in range(b)] - #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + #creates a matrix for the plane partition populated by 0s + #EX: [[0,0,0], [0,0,0], [0,0,0]] #ac format ex: [x,y,z] for ac in acl: x = ac[0] @@ -1710,10 +1778,37 @@ def from_antichain(self, acl): def from_order_ideal(self, I) -> PP: r""" - Return the plane partition corresponding to an order ideal in the - poset given in :meth:`to_poset`. + Return the cylically symmetric plane partition corresponding + to an order ideal in the poset given in :meth:`to_poset`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), (1, 0, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2)] + sage: PP.from_order_ideal(I) + Plane partition [[3, 3, 3], [3, 3, 3], [3, 3, 2]] """ - return self.from_antichain(self.to_poset().order_ideal_generators(I)) + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def random_element(self) -> PP: + r""" + Return a uniformly random element of ``self``. + + ALGORITHM: + + This uses the + :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` + method and the natural bijection between cyclically symmetric plane + partitions and order ideals in an associated poset. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: PP.random_element() + Plane partition [[3, 2, 2], [3, 1], [1, 1]] + """ + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) + return self.element_class(self, Z, check=False) def __iter__(self) -> Iterator: """ @@ -1752,8 +1847,14 @@ def cardinality(self) -> Integer: A = self._box[0] B = self._box[1] C = self._box[2] - 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)) + 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) @@ -1785,9 +1886,13 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='TSPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions must match") + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0], box_size[1], box_size[2])) super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TSPP' @@ -1803,8 +1908,17 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def to_poset(self): - """ - MAKE SURE DOC EXPLICITLY DESCRIBES WHAT FUNDAMENTAL DOMAIN LOOKS LIKE + r""" + Returns a poset whose order ideals are in bijection with totally + symmetric plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: PP.to_poset() + Finite poset containing 10 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True """ a=self._box[0] b=self._box[1] @@ -1818,10 +1932,22 @@ def to_poset(self): return Poset((pl,cmp)) def from_antichain(self, acl) -> PP: + r""" + Return the totally symmetric plane partition corresponding to an antichain + in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: A = [(0, 0, 2), (0, 1, 1)] + sage: PP.from_antichain(A) + Plane partition [[3, 2, 1], [2, 1], [1]] + """ a=self._box[0] b=self._box[1] c=self._box[2] - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane + #partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] for ac in acl: x = ac[0] y = ac[1] @@ -1837,7 +1963,8 @@ def from_antichain(self, acl) -> PP: ppMatrix[y][x] = (z+1) #z,y,x - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partitian format + #for each value in current antichain, fill in the rest of the matrix by + #rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format if acl != []: for i in range(b): i = b-(i+1) @@ -1853,8 +1980,21 @@ def from_antichain(self, acl) -> PP: ppMatrix[i][j] = max(iValue,jValue) return self.element_class(self, ppMatrix) - def random_element(self) -> PP: - return self.to_poset().from_antichain(self.to_poset().random_antichain()) + def from_order_ideal(self, I) -> PP: + r""" + Return the totally symmetric plane partition corresponding + to an order ideal in the poset given in :meth:`to_poset`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1)] + sage: PP.from_order_ideal(I) + Plane partition [[3, 2, 1], [2, 1], [1]] + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def __iter__(self) -> Iterator: """ @@ -1921,9 +2061,13 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([5,3,1], symmetry='SCPP') + Traceback (most recent call last): + ... + ValueError: dimensions (5,3,1) cannot all be odd """ if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("dimensions cannot all be odd") + raise ValueError("dimensions ({},{},{}) cannot all be odd".format(box_size[0],box_size[1],box_size[2])) super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SCPP' @@ -2131,11 +2275,19 @@ def __init__(self, box_size): sage: PP = PlanePartitions([3,3,2], symmetry='TCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([3,3,3], symmetry='TCPP') + Traceback (most recent call last): + ... + ValueError: z dimension (3) must be even + sage: PlanePartitions([4,3,2], symmetry='TCPP') + Traceback (most recent call last): + ... + ValueError: x and y dimensions (4 and 3) must be equal """ if (box_size[2] % 2 == 1): - raise ValueError("z dimension must be even") + raise ValueError("z dimension ({}) must be even".format(box_size[2])) if box_size[0] != box_size[1]: - raise ValueError("x and y dimensions must be equal") + raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0],box_size[1])) super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TCPP' @@ -2214,13 +2366,21 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,2,2], symmetry='SSCPP') + Traceback (most recent call last): + ... + ValueError: x and y dimensions (4 and 2) must be equal + sage: PlanePartitions([4,4,3], symmetry='SSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,4,3) must all be even """ if box_size[0]!=box_size[1]: - raise ValueError("x and y dimensions must be equal") + raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) if (box_size[0] % 2 == 1 or box_size[1] % 2 == 1 or box_size[2] % 2 == 1): - raise ValueError("all dimensions must be even") + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SSCPP' @@ -2255,6 +2415,23 @@ def __iter__(self) -> Iterator: return def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of symmetric self-complementary plane partitions inside a + `2a \times 2a \times 2b` box is equal to + + .. MATH:: + + \prod_{i=1}^{a}\prod_{j=1}^{a} \frac{i + j + b - 1}{i + j - 1} + + The number of symmetric self-complementary plane partitions inside a + `2a+1 \times 2a+1 \times 2b` box is equal to + + .. MATH:: + + \prod_{i=1}^{a}\prod_{j=1}^{a+1} \frac{i + j + b - 1}{i + j - 1} + """ r=self._box[0] s=self._box[1] t=self._box[2] @@ -2294,11 +2471,19 @@ def __init__(self, box_size): sage: PP = PlanePartitions([2,2,2], symmetry='CSTCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='CSTCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + sage: PlanePartitions([3,3,3], symmetry='CSTCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (3,3,3) must all be even """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions must match") + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) if box_size[0] % 2 == 1: - raise ValueError("all dimensions must be even") + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSTCPP' @@ -2328,11 +2513,22 @@ def __iter__(self) -> Iterator: return def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of cyclically symmetric transpose complement plane partitions + inside a `2a \times 2a \times 2a` box is equal to + + .. MATH:: + + \prod_{i=0}^{a-1} \frac{(3i+1)(6i)!(2i)!}{(4i+1)!(4i)!} + + """ a=self._box[0] b=self._box[1] c=self._box[2] if a == b and b == c and a % 2 == 0: - return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range(1+(a/2)-1))) + return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range((a/2)))) return Integer(0) # Class 9 @@ -2360,11 +2556,19 @@ def __init__(self, box_size): sage: PP = PlanePartitions([2,2,2], symmetry='CSSCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='CSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + sage: PlanePartitions([3,3,3], symmetry='CSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (3,3,3) must all be even """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions must match") + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) if box_size[0] % 2 == 1: - raise ValueError("all dimensions must be even") + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'CSSCPP' @@ -2394,6 +2598,16 @@ def __iter__(self) -> Iterator: return def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of cyclically symmetric self-complementary plane partitions + inside a `2a \times 2a \times 2a` box is equal to + + .. MATH:: + + \left(\prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!})\right)^2 + """ a=self._box[0] b=self._box[1] c=self._box[2] @@ -2427,11 +2641,19 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,4,4], symmetry='TSSCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='TSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + sage: PlanePartitions([3,3,3], symmetry='TSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (3,3,3) must all be even """ - if (box_size[0] != box_size[1]) or (box_size[1] != box_size[2]): - raise ValueError("all dimensions must be equal") - if box_size[0] % 2 != 0: - raise ValueError("all dimensions must be even") + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) + if box_size[0] % 2 == 1: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'TSSCPP' @@ -2447,6 +2669,18 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def to_poset(self): + r""" + Returns a poset whose order ideals are in bijection with + totally symmetric self-complementary plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: PP.to_poset() + Finite poset containing 4 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True + """ cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) def componentwise_comparer(thing1,thing2): if len(thing1) == len(thing2): @@ -2469,12 +2703,25 @@ def componentwise_comparer(thing1,thing2): return Poset((pl,cmp)) def from_antichain(self, acl) -> PP: + r""" + Return the totally symmetric self-complementary plane partition + corresponding to an antichain in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: A = [(0, 0, 1), (1, 1, 0)] + sage: PP.from_antichain(A) + Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 4, 3, 1], [6, 5, 4, 3, 2, 1], [5, 4, 3, 2, 1], [5, 3, 2, 1, 1], [3, 1, 1]] + """ #ac format ex: [x,y,z] a=self._box[0] b=self._box[1] c=self._box[2] n=a - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + ppMatrix = [[0] * (c) for i in range(b)] + #creates a matrix for the plane parition populated by 0s + #EX: [[0,0,0], [0,0,0], [0,0,0]] width = n/2 - 1 height = n/2 - 1 @@ -2551,8 +2798,19 @@ def from_antichain(self, acl) -> PP: ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] return self.element_class(self, ppMatrix) + def from_order_ideal(self, I) -> PP: + r""" + Return the totally symmetric self-complementary plane partition corresponding + to an order ideal in the poset given in :meth:`to_poset`. + EXAMPLES:: + sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: I = [(0, 0, 0), (0, 1, 0), (1, 1, 0)] + sage: PP.from_order_ideal(I) + Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 3, 3, 1], [6, 5, 5, 3, 3, 1], [5, 3, 3, 1, 1], [5, 3, 3, 1, 1], [3, 1, 1]] + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) def __iter__(self) -> Iterator: @@ -2569,4 +2827,22 @@ def __iter__(self) -> Iterator: yield self.from_antichain(acl) return + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of totally symmetric self-complementary plane partitions + inside a `2a \times 2a \times 2a` box is equal to + + .. MATH:: + + \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}) + """ + a=self._box[0] + b=self._box[1] + c=self._box[2] + if a == b and b == c and a % 2 == 0: + return Integer(prod( ((factorial(3*i+1)/(factorial(a/2+i)) for i in range((a/2)))))) + return Integer(0) + From 6347c1cd67cd6e3c4bb76a2c270864c73b660d42 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Fri, 27 Aug 2021 14:50:52 -0500 Subject: [PATCH 50/74] continuing doctest cleaup, working on __contains__, pausing at SCPP --- src/sage/combinat/plane_partition.py | 187 ++++++++++++++++++++++----- 1 file changed, 152 insertions(+), 35 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index e57bbcaf3c0..84941ad7760 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -35,6 +35,7 @@ from sage.combinat.posets.poset_examples import posets from sage.categories.cartesian_product import cartesian_product from sage.rings.integer import Integer +from sage.rings.all import ZZ from sage.misc.all import prod from sage.combinat.tableau import Tableau from sage.arith.misc import Sigma @@ -79,6 +80,35 @@ #@add_metaclass(InheritComparisonClasscallMetaclass) class PlanePartition(ClonableList, metaclass=InheritComparisonClasscallMetaclass): + r""" + A plane partition. + + A *plane partition* is a stack of cubes in the positive orthant. + + INPUT: + + - ``PP`` -- a list of lists which represents a tableau + + - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, + where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, + `y`-axis, `z`-axis, respectively; if this is not given, it is + determined by the smallest box bounding ``PP`` + + OUTPUT: + + The plane partition whose tableau representation is ``PP``. + + EXAMPLES:: + + sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: PP + Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] + + TESTS:: + + sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: TestSuite(PP).run() + """ @staticmethod def __classcall_private__(cls, PP): """ @@ -153,7 +183,18 @@ def check(self): Traceback (most recent call last): ... ValueError: Not weakly decreasing along columns + sage: d = PlanePartition([[2,-1],[-2]]) + Traceback (most recent call last): + ... + ValueError: Entries not all nonnegative + sage: e = PlanePartition([[3/2,1],[.5]]) + Traceback (most recent call last): + ... + ValueError: Entries not all integers + """ + if not all(all(a in ZZ for a in b) for b in self): + raise ValueError("Entries not all integers") for row in self: if not all(c >= 0 for c in row): raise ValueError("Entries not all nonnegative") @@ -781,7 +822,10 @@ def is_SCPP(self) -> bool: r""" Return whether ``self`` is a self-complementary plane partition. - + Note that the complement of a plane partition (and thus the property of + being self-complementary) is dependent on the choice of a box that is + contained in. If no parent/bounding box is specified, the box is taken + to be the smallest box that contains the plane partition. @@ -941,7 +985,7 @@ def maximal_boxes(self) -> list: return [list(oi_elem) for oi_elem in oi] def cyclically_rotate(self, preserve_parent=False) -> PP: - """ + r""" Return the cyclic rotation of ``self``. By default, if the parent of ``self`` consists of plane @@ -1081,15 +1125,23 @@ def __contains__(self, pp): False """ - for row in pp: - if not all(c >= 0 for c in row): - return False - if not all(row[i] >= row[i+1] for i in range(len(row)-1)): - return False - for row, next in zip(pp, pp[1:]): - if not all(row[c] >= next[c] for c in range(len(next))): + if isinstance(pp, PlanePartition): + return True + if isinstance(pp, (list, tuple)): + if not pp: + return True + if not all(all(a in ZZ for a in b) for b in pp): return False - return True + for row in pp: + if not all(c >= 0 for c in row): + return False + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + return False + for row, next in zip(pp, pp[1:]): + if not all(row[c] >= next[c] for c in range(len(next))): + return False + return True + return False @@ -1164,7 +1216,7 @@ def __init__(self, box_size): EXAMPLES:: - sage: PP = PlanePartitions((4,3,2)) + sage: PP = PlanePartitions([4,3,2]) sage: TestSuite(PP).run() """ super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) @@ -1265,7 +1317,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((1,2,1))) + sage: list(PlanePartitions([1,2,1])) [Plane partition [], Plane partition [[1]], Plane partition [[1, 1]]] """ @@ -1297,7 +1349,7 @@ def cardinality(self) -> Integer: EXAMPLES:: - sage: P = PlanePartitions((4,3,5)) + sage: P = PlanePartitions([4,3,5]) sage: P.cardinality() 116424 """ @@ -1316,7 +1368,7 @@ def box(self) -> Tuple: EXAMPLES:: - sage: P = PlanePartitions((4,3,5)) + sage: P = PlanePartitions([4,3,5]) sage: P.box() (4, 3, 5) """ @@ -1334,7 +1386,7 @@ def random_element(self) -> PP: EXAMPLES:: - sage: P = PlanePartitions((4,3,5)) + sage: P = PlanePartitions([4,3,5]) sage: P.random_element() Plane partition [[4, 3, 3], [4], [2]] """ @@ -1371,7 +1423,7 @@ def __init__(self, n): def _repr_(self) -> str: """ - EXAMPLES:: + TESTS:: sage: PlanePartitions(3) Plane partitions of size 3 @@ -1379,7 +1431,15 @@ def _repr_(self) -> str: return "Plane partitions of size {}".format(self._n) def __contains__(self, x) -> bool: - return PlanePartitions.__contains__(self, x) and x.number_of_boxes() == self._n + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions(4) + True + sage: [[2,1],[1]] in PlanePartitions(3) + False + """ + return PlanePartitions.__contains__(self, x) and PlanePartition(x).number_of_boxes() == self._n def __iter__(self) -> Iterator: r""" @@ -1512,7 +1572,19 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __contains__(self, x) -> bool: - return PlanePartitions.__contains__(self, x) and x.is_SPP() + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='SPP') + True + sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='SPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='SPP') + False + """ + P = PlanePartition(x) + max = (P._max_x, P._max_y, P._max_z) + return PlanePartitions.__contains__(self, x) and P.is_SPP() and all( a<=b for a,b in zip(max,self._box)) def to_poset(self): @@ -1602,7 +1674,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((2,2,1), symmetry='SPP')) + sage: list(PlanePartitions([2,2,1], symmetry='SPP')) [Plane partition [], Plane partition [[1, 1], [1, 1]], Plane partition [[1, 1], [1]], @@ -1625,7 +1697,7 @@ def cardinality(self) -> Integer: EXAMPLES:: - sage: P = PlanePartitions((3,3,2), symmetry='SPP') + sage: P = PlanePartitions([3,3,2], symmetry='SPP') sage: P.cardinality() 35 """ @@ -1704,6 +1776,21 @@ def _repr_(self) -> str: return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='CSPP') + True + sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='CSPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='CSPP') + False + """ + P = PlanePartition(x) + max = (P._max_x, P._max_y, P._max_z) + return PlanePartitions.__contains__(self, x) and P.is_CSPP() and all( a<=b for a,b in zip(max,self._box)) + def to_poset(self): """ Return a partially ordered set whose order ideals are in bijection with @@ -1816,7 +1903,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((2,2,2), symmetry='CSPP')) + sage: list(PlanePartitions([2,2,2], symmetry='CSPP')) [Plane partition [], Plane partition [[2, 2], [2, 2]], Plane partition [[2, 2], [2, 1]], @@ -1840,7 +1927,7 @@ def cardinality(self) -> Integer: EXAMPLES:: - sage: P = PlanePartitions((4,4,4), symmetry='CSPP') + sage: P = PlanePartitions([4,4,4], symmetry='CSPP') sage: P.cardinality() 132 """ @@ -1907,6 +1994,21 @@ def _repr_(self) -> str: return "Totally symmetric plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='TSPP') + True + sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='TSPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='TSPP') + False + """ + P = PlanePartition(x) + max = (P._max_x, P._max_y, P._max_z) + return PlanePartitions.__contains__(self, x) and P.is_TSPP() and all( a<=b for a,b in zip(max,self._box)) + def to_poset(self): r""" Returns a poset whose order ideals are in bijection with totally @@ -2002,7 +2104,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((2,2,2), symmetry='TSPP')) + sage: list(PlanePartitions([2,2,2], symmetry='TSPP')) [Plane partition [], Plane partition [[2, 2], [2, 2]], Plane partition [[2, 2], [2, 1]], @@ -2026,7 +2128,7 @@ def cardinality(self) -> Integer: EXAMPLES:: - sage: P = PlanePartitions((4,4,4), symmetry='TSPP') + sage: P = PlanePartitions([4,4,4], symmetry='TSPP') sage: P.cardinality() 66 """ @@ -2072,6 +2174,21 @@ def __init__(self, box_size): self._box = box_size self._symmetry = 'SCPP' + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='SCPP') + True + sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='SCPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='SCPP') + False + """ + P = PlanePartition(x) + max = (P._max_x, P._max_y, P._max_z) + return PlanePartitions.__contains__(self, x) and P.is_SCPP() and all( a<=b for a,b in zip(max,self._box)) + def _repr_(self) -> str: """ EXAMPLES:: @@ -2088,7 +2205,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((2,2,2), symmetry='SCPP')) + sage: list(PlanePartitions([2,2,2], symmetry='SCPP')) [Plane partition [[1, 1], [1, 1]], Plane partition [[2], [2]], Plane partition [[2, 1], [1]], @@ -2219,15 +2336,15 @@ def cardinality(self) -> Integer: EXAMPLES:: - sage: P = PlanePartitions((4,4,4), symmetry='SCPP') + sage: P = PlanePartitions([4,4,4], symmetry='SCPP') sage: P.cardinality() 400 - sage: P = PlanePartitions((5,4,4), symmetry='SCPP') + sage: P = PlanePartitions([5,4,4], symmetry='SCPP') sage: P.cardinality() 1000 - sage: P = PlanePartitions((5,5,4), symmetry='SCPP') + sage: P = PlanePartitions([5,5,4], symmetry='SCPP') sage: P.cardinality() 2500 """ @@ -2308,7 +2425,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((3,3,2), symmetry='TCPP')) + sage: list(PlanePartitions([3,3,2], symmetry='TCPP')) [Plane partition [[2, 2, 1], [2, 1], [1]], Plane partition [[2, 1, 1], [2, 1, 1], [1]], Plane partition [[2, 2, 1], [1, 1], [1, 1]], @@ -2331,7 +2448,7 @@ def cardinality(self) -> Integer: .. MATH:: - \binom{b+1-1}{a-1}\prod_{1\leq i\leq j a-2} \frac{i + j + 2b - 1}{i + j - 1} + \binom{b+1-1}{a-1}\prod_{1\leq i,j \leq a-2} \frac{i + j + 2b - 1}{i + j - 1} """ a=self._box[0] @@ -2401,7 +2518,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((4,4,2), symmetry='SSCPP')) + sage: list(PlanePartitions([4,4,2], symmetry='SSCPP')) [Plane partition [[2, 2, 2, 1], [2, 2, 1], [2, 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]], @@ -2504,7 +2621,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((2,2,2), symmetry='CSTCPP')) + sage: list(PlanePartitions([2,2,2], symmetry='CSTCPP')) [Plane partition [[2, 1], [1]]] """ for p in PlanePartitions(self._box): @@ -2589,7 +2706,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((2,2,2), symmetry='CSSCPP')) + sage: list(PlanePartitions([2,2,2], symmetry='CSSCPP')) [Plane partition [[2, 1], [1]]] """ for p in PlanePartitions(self._box): @@ -2606,7 +2723,7 @@ def cardinality(self) -> Integer: .. MATH:: - \left(\prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!})\right)^2 + \left(\prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}\right)^2 """ a=self._box[0] b=self._box[1] @@ -2819,7 +2936,7 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions((4,4,4), symmetry='TSSCPP')) + 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]]] """ From acb09c98e1b5697004e659b98b5b915884a70358 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Mon, 30 Aug 2021 18:13:41 -0500 Subject: [PATCH 51/74] Added examples for some cardinality methods, maybe some other prior changes --- src/sage/combinat/plane_partition.py | 101 +++++++++++++++------------ 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 84941ad7760..144e2e11fb5 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -11,6 +11,7 @@ # **************************************************************************** # Copyright (C) 2016 Jang Soo Kim , # 2016 Jessica Striker +# 2021 Kevin Dilks # # Distributed under the terms of the GNU General Public License (GPL) # @@ -46,37 +47,6 @@ PP = NewType('PP', 'PlanePartition') -#class PlanePartition(ClonableArray, -# metaclass=InheritComparisonClasscallMetaclass): -# r""" -# A plane partition. - -# A *plane partition* is a stack of cubes in the positive orthant. - -# INPUT: - -# - ``PP`` -- a list of lists which represents a tableau - -# - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, -# where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, -# `y`-axis, `z`-axis, respectively; if this is not given, it is -# determined by the smallest box bounding ``PP`` - -# OUTPUT: - -# The plane partition whose tableau representation is ``PP``. - -# EXAMPLES:: - -# sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) -# sage: PP -# Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] - -# TESTS:: - -# sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) -# sage: TestSuite(PP).run() -# """ #@add_metaclass(InheritComparisonClasscallMetaclass) class PlanePartition(ClonableList, metaclass=InheritComparisonClasscallMetaclass): @@ -823,7 +793,7 @@ def is_SCPP(self) -> bool: Return whether ``self`` is a self-complementary plane partition. Note that the complement of a plane partition (and thus the property of - being self-complementary) is dependent on the choice of a box that is + being self-complementary) is dependent on the choice of a box that it is contained in. If no parent/bounding box is specified, the box is taken to be the smallest box that contains the plane partition. @@ -1194,6 +1164,10 @@ def _repr_(self) -> str: class PlanePartitions_box(PlanePartitions): r""" All plane partitions that fit inside a box of a specified size. + + By convention, a plane partition in an `a \times b \times c` box + will have at most 'a' rows, of lengths at most 'b', with entries + at most 'c'. """ @staticmethod def __classcall_private__(cls, box_size): @@ -1512,6 +1486,12 @@ def cardinality(self) -> Integer: where ``\sigma_k(n)`` is the sum of the kth powers of divisors of n. + EXAMPLES:: + + sage: P = PlanePartitions(17) + sage: P.cardinality() + 18334 + """ PPn = [1] for i in range(1,1+self._n): @@ -2180,14 +2160,17 @@ def __contains__(self, x) -> bool: sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='SCPP') True - sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='SCPP') + sage: [[2,1],[1]] in PlanePartitions([3,2,2], symmetry='SCPP') + False + sage: [[2,1],[1]] in PlanePartitions([2,1,1], symmetry='SCPP') False sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='SCPP') False """ - P = PlanePartition(x) - max = (P._max_x, P._max_y, P._max_z) - return PlanePartitions.__contains__(self, x) and P.is_SCPP() and all( a<=b for a,b in zip(max,self._box)) + #P = PlanePartitions(self._box)(x) + #max = (P._max_x, P._max_y, P._max_z) + #return PlanePartitions.__contains__(self, x) and P.is_SCPP() and all( a<=b for a,b in zip(max,self._box)) + return x in PlanePartitions(self._box) and PlanePartitions(self._box)(x).is_SCPP() def _repr_(self) -> str: """ @@ -2205,14 +2188,16 @@ def __iter__(self) -> Iterator: EXAMPLES:: - sage: list(PlanePartitions([2,2,2], symmetry='SCPP')) - [Plane partition [[1, 1], [1, 1]], - Plane partition [[2], [2]], - Plane partition [[2, 1], [1]], - Plane partition [[2, 2]]] + sage: list(PlanePartitions([3,2,2], symmetry='SCPP')) + [Plane partition [[1, 1], [1, 1], [1, 1]], + Plane partition [[2, 1], [1, 1], [1]], + Plane partition [[2, 2], [1, 1]], + Plane partition [[2], [2], [2]], + Plane partition [[2, 1], [2], [1]], + Plane partition [[2, 2], [2]]] """ - a=self._box[0] - b=self._box[1] + b=self._box[0] + a=self._box[1] c=self._box[2] def Partitions_inside_lambda(la): "Returns the list of partitions contained in la with the same number of parts including 0s." @@ -2449,6 +2434,12 @@ def cardinality(self) -> Integer: .. MATH:: \binom{b+1-1}{a-1}\prod_{1\leq i,j \leq a-2} \frac{i + j + 2b - 1}{i + j - 1} + + EXAMPLES:: + + sage: P = PlanePartitions([3,3,2], symmetry='TCPP') + sage: P.cardinality() + 5 """ a=self._box[0] @@ -2548,6 +2539,13 @@ def cardinality(self) -> Integer: .. MATH:: \prod_{i=1}^{a}\prod_{j=1}^{a+1} \frac{i + j + b - 1}{i + j - 1} + + EXAMPLES:: + + sage: P = PlanePartitions([4,4,2], symmetry='SSCPP') + sage: P.cardinality() + 6 + """ r=self._box[0] s=self._box[1] @@ -2640,6 +2638,11 @@ def cardinality(self) -> Integer: \prod_{i=0}^{a-1} \frac{(3i+1)(6i)!(2i)!}{(4i+1)!(4i)!} + EXAMPLES:: + + sage: P = PlanePartitions([6,6,6], symmetry='CSTCPP') + sage: P.cardinality() + 11 """ a=self._box[0] b=self._box[1] @@ -2724,6 +2727,12 @@ def cardinality(self) -> Integer: .. MATH:: \left(\prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}\right)^2 + + EXAMPLES:: + + sage: P = PlanePartitions([6,6,6], symmetry='CSSCPP') + sage: P.cardinality() + 49 """ a=self._box[0] b=self._box[1] @@ -2954,6 +2963,12 @@ def cardinality(self) -> Integer: .. MATH:: \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}) + + EXAMPLES:: + + sage: P = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: P.cardinality() + 7 """ a=self._box[0] b=self._box[1] From 3856cc65e25ea6e0ec2b97a6cf59e299cecdbbfa Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 1 Sep 2021 10:58:24 -0500 Subject: [PATCH 52/74] Continued doc cleanup --- src/sage/combinat/plane_partition.py | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 144e2e11fb5..34d4fb3f83e 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1121,10 +1121,10 @@ class PlanePartitions_all(PlanePartitions): r""" All plane partitions. - .. TODO: + .. TODO:: - Consider giving this the structure of disjoint union of the classes - PlanePartitions(n) for n an integer. + Consider giving this the structure of disjoint union of the classes + PlanePartitions(n) for n an integer. """ @@ -1479,11 +1479,11 @@ def cardinality(self) -> Integer: Calculated using the recurrence relation - .. MATH: + .. MATH:: - PL(n) = \sum_{k=1}^n PL(n-k)\sigma_2(k) + PL(n) = \sum_{k=1}^n PL(n-k)\sigma_2(k) - where ``\sigma_k(n)`` is the sum of the kth powers of + where `\sigma_k(n)` is the sum of the kth powers of divisors of n. EXAMPLES:: @@ -1667,13 +1667,13 @@ def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of symmetric plane partitions inside an `r \times r \times t` + The number of symmetric plane partitions inside an `a \times a \times b` box is equal to .. MATH:: - \prod_{i=1}^{r} \frac{2*i + t - 1}{2*i - 1} * - \prod_{1 \leq i \leq j \leq r} \frac{i+j+t-1}{i+j-1} + \left(\prod_{i=1}^{a} \frac{2i + b - 1}{2i - 1}\right) + \left(\prod_{1 \leq i < j \leq a} \frac{i+j+b-1}{i+j-1}\right) EXAMPLES:: @@ -1898,12 +1898,12 @@ def cardinality(self) -> Integer: Return the cardinality of ``self``. The number of cyclically symmetric plane partitions inside an - `r \times r \times r` box is equal to + `a \times a \times a` box is equal to .. MATH:: - \left(\prod_{i=1}^{r} \frac{3i - 1}{3i - 2}\right) - \left(\prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{2i+j-1}\right) + \left(\prod_{i=1}^{a} \frac{3i - 1}{3i - 2}\right) + \left(\prod_{1 \leq i < j \leq a} \frac{i+j+a-1}{2i+j-1}\right) EXAMPLES:: @@ -2100,11 +2100,11 @@ def cardinality(self) -> Integer: Return the cardinality of ``self``. The number of totally symmetric plane partitions inside an - `r \times r \times r` box is equal to + `a \times a \times a` box is equal to .. MATH:: - \prod_{1 \leq i \leq j \leq r} \frac{i+j+r-1}{i+2j-2} + \prod_{1 \leq i \leq j \leq a} \frac{i+j+a-1}{i+2j-2} EXAMPLES:: @@ -2534,7 +2534,7 @@ def cardinality(self) -> Integer: \prod_{i=1}^{a}\prod_{j=1}^{a} \frac{i + j + b - 1}{i + j - 1} The number of symmetric self-complementary plane partitions inside a - `2a+1 \times 2a+1 \times 2b` box is equal to + `(2a+1) \times (2a+1) \times 2b` box is equal to .. MATH:: @@ -2962,7 +2962,7 @@ def cardinality(self) -> Integer: .. MATH:: - \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}) + \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!} EXAMPLES:: From 84fb5e0369b7671a606d28953d76f75ff8574f9a Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 1 Sep 2021 17:18:11 -0500 Subject: [PATCH 53/74] Starting better description of input for PlanePartitions --- src/sage/combinat/plane_partition.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 34d4fb3f83e..d8100b73fa1 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1017,12 +1017,27 @@ class PlanePartitions(UniqueRepresentation, Parent): r""" A factory class for plane partitions. + PlanePartitions() returns the class of all plane partitions. + + PlanePartitions(n) return the class of all plane partitions with `n` boxes. + PlanePartitions([a,b,c]) returns the class of plane partitions that fit inside an a \times b \times c box. - Optional keyword is 'symmetry'. + Optional keyword is 'symmetry', which gives all plane partitions inside + a box of the specified size satisfying certain symmetry conditions. + + - 'SPP' Symmetric plane partitions + - 'CSPP' Cyclic plane partitions + - 'TSPP' Totally symmetric plane partitions + - 'SCPP' Self-complementary plane partitions + - 'TCPP' Transpose complement plane partitions + - 'SSCPP' Symmetric self-complementary plane partitions + - 'CSTCPP' Cyclically symmetric transpose complement plane partitions + - 'CSSCPP' Cyclically symmetric self-complementary plane partitions + - 'TSSCPP' Totally symmetric self-complementary plane partitions + - Describe options. """ @staticmethod @@ -1193,10 +1208,12 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,3,2]) sage: TestSuite(PP).run() """ + #PlanePartitions.__init__(self) super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = None + def _repr_(self) -> str: """ From 9948f542bf7ba94b951fbf93ea49326fc147ffe5 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 1 Sep 2021 18:41:50 -0500 Subject: [PATCH 54/74] added richcmp method --- src/sage/combinat/plane_partition.py | 62 ++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index d8100b73fa1..ce22149c722 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -28,6 +28,7 @@ from sage.structure.list_clone import ClonableList, ClonableArray from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.structure.richcmp import richcmp, richcmp_method from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -48,7 +49,7 @@ -#@add_metaclass(InheritComparisonClasscallMetaclass) +@richcmp_method class PlanePartition(ClonableList, metaclass=InheritComparisonClasscallMetaclass): r""" A plane partition. @@ -110,8 +111,14 @@ def __init__(self, parent, pp, check=True): sage: a = PlanePartitions()([[2,1],[1]]) sage: b = PlanePartitions([2,2,2])([[2,1],[1]]) sage: c = PlanePartitions(4)([[2,1],[1]]) - - Add more tests to show which parent a,b,c receive, check that a==b, and b==c, but a is not b, and b is not c. + sage: a == b + True + sage: a is b + False + sage: a == c + True + sage: a is c + False """ if isinstance(pp, PlanePartition): @@ -137,6 +144,54 @@ def __init__(self, parent, pp, check=True): else: (self._max_x, self._max_y, self._max_z) = self.parent()._box + def __richcmp__(self, other, op): + r""" + Compare ``self`` to ``other``. + + .. TODO:: + + This overwrites the comparison check of + :class:`~sage.structure.list_clone.ClonableArray` + in order to circumvent the coercion framework. + Eventually this should be solved more elegantly, + for example along the lines of what was done for + `k`-tableaux. + + For now, this compares two elements by their underlying + defining lists. + + INPUT: + + ``other`` -- the element that ``self`` is compared to + + OUTPUT: + + A Boolean. + + TESTS:: + + sage: t = PlanePartition([[2,1],[1]]) + sage: t == 0 + False + sage: t == PlanePartitions(4)([[2,1],[1]]) + True + + sage: s = PlanePartition([[3,1],[1]]) + sage: s != [] + True + + sage: t < s + True + sage: s < t + False + sage: s > t + True + """ + if isinstance(other, PlanePartition): + return richcmp(list(self), list(other), op) + else: + return richcmp(list(self), other, op) + def check(self): """ Check to see that ``self`` is a valid plane partition. @@ -1208,7 +1263,6 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,3,2]) sage: TestSuite(PP).run() """ - #PlanePartitions.__init__(self) super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = None From 6ef9c0c6d2ba42b0a4c5b0050bafddbc00bc4f16 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 10:05:38 -0500 Subject: [PATCH 55/74] Added to PlanePartitions doc --- src/sage/combinat/plane_partition.py | 114 +++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index ce22149c722..075b6de5b30 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1077,22 +1077,106 @@ class PlanePartitions(UniqueRepresentation, Parent): PlanePartitions(n) return the class of all plane partitions with `n` boxes. PlanePartitions([a,b,c]) returns the class of plane partitions that fit - inside an a \times b \times c box. - - Optional keyword is 'symmetry', which gives all plane partitions inside - a box of the specified size satisfying certain symmetry conditions. - - - 'SPP' Symmetric plane partitions - - 'CSPP' Cyclic plane partitions - - 'TSPP' Totally symmetric plane partitions - - 'SCPP' Self-complementary plane partitions - - 'TCPP' Transpose complement plane partitions - - 'SSCPP' Symmetric self-complementary plane partitions - - 'CSTCPP' Cyclically symmetric transpose complement plane partitions - - 'CSSCPP' Cyclically symmetric self-complementary plane partitions - - 'TSSCPP' Totally symmetric self-complementary plane partitions - + inside an `a \times b \times c` box. + + PlanePartitions([a,b,c]) has optional keyword is 'symmetry', which gives all + plane partitions inside a box of the specified size satisfying certain + symmetry conditions. + + - ``symmetry='SPP'`` gives the class of symmetric plane partitions. which + is all plane partitions fixed under reflection across the diagonal. + Requires that `a = b`. + + - ``symmetry='CSPP'`` gives the class of cyclic plane partitions, which + is all plane partitions fixed under cyclic rotation of coordinates. + Requires that `a = b = c`. + - ``symmetry='TSPP'`` gives the class of totally symmetric plane partitions, + which is all plane partitions fixed under any interchanging of coordinates. + Requires that `a = b = c`. + + - ``symmetry='SCPP'`` gives the class of self-complementary plane partitions. + which is all plane partitions that are equal to their own complement + in the specified box. Requires at least one of `a,b,c` be even. + + - ``symmetry='TCPP'`` gives the class of transpose complement plane partitions, + which is all plane partitions whose complement in the box of the specified + size is equal to their transpose. Requires `a = b` and at least one of + `a,b,c` be even. + + - ``symmetry='SSCPP'`` gives the class of symmetric self-complementary + plane partitions, which is all plane partitions that are both + symmetric and self-complementary. Requires `a = b` and at least one of + `a,b,c` be even. + + - ``symmetry='CSTCPP'`` gives the class of cyclically symmetric transpose + complement plane partitions, which is all plane partitions that are + both symmetric and equal to the transpose of their complement. Requires + `a = b = c`. + + - ``symmetry='CSSCPP'`` gives the class of cyclically symmetric + self-complementary plane partitions, which is all plane partitions that + are both cyclically symmetric and self-complementary. Requires `a = b = c` + and at least one of `a,b,c` be even. + + - ``symmetry='TSSCPP'`` gives the class of totally symmetric + self-complementary plane partitions, which is all plane partitions that + are totally symmetric and also self-complementary. Requires `a = b = c` + and at least one of `a,b,c` be even. + + EXAMPLES: + + If no arguments are passed, then the class of all plane partitions is returned:: + + sage: PlanePartitions() + Plane Partitions + sage: [[2,1],[1]] in PlanePartitions() + True + + If an integer `n` is passed, then the class of plane partitions of `n` is returned:: + + sage: PlanePartitions(3) + Plane partitions of size 3 + sage: PlanePartitions(3).list() + [Plane partition [[3]], + Plane partition [[2, 1]], + Plane partition [[1, 1, 1]], + Plane partition [[2], [1]], + Plane partition [[1, 1], [1]], + Plane partition [[1], [1], [1]]] + + If a three-element tuple or list `[a,b,c]` is passed, then the class of all + plane partitions that fit inside and `a\times b\times c` box is returned:: + + sage: PlanePartitions([2,2,2]) + Plane partitions inside a 2 x 2 x 2 box + sage: [[2,1],[1]] in PlanePartitions([2,2,2]) + True + + If an additional keyword ``symmetry`` is pass along with a three-element + tuple or list `[a,b,c]`, then the class of all plane partitions that fit + inside an `a\times b\times c` box with the specified symmetry is returned:: + + sage: PlanePartitions([2,2,2], symmetry='CSPP') + Cyclically symmetric plane partitions inside a 2 x 2 x 2 box + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='CSPP') + True + + .. SEEALSO:: + + - :class:`PlanePartition` + - :class:`PlanePartitions_all` + - :class:`PlanePartitions_n` + - :class:`PlanePartitions_box` + - :class:`PlanePartitions_SPP` + - :class:`PlanePartitions_CSPP` + - :class:`PlanePartitions_TSPP` + - :class:`PlanePartitions_SCPP` + - :class:`PlanePartitions_TCPP` + - :class:`PlanePartitions_SSCPP` + - :class:`PlanePartitions_CSTCPP` + - :class:`PlanePartitions_CSSCPP` + - :class:`PlanePartitions_TSSCPP` """ @staticmethod From e7b3999ee8aba946e47090cf5e4e609689f4e492 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 10:15:21 -0500 Subject: [PATCH 56/74] marked random element methods as random --- src/sage/combinat/plane_partition.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 075b6de5b30..fb307f6c4b6 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1516,7 +1516,7 @@ def random_element(self) -> PP: EXAMPLES:: sage: P = PlanePartitions([4,3,5]) - sage: P.random_element() + sage: P.random_element() # random Plane partition [[4, 3, 3], [4], [2]] """ Z = self.from_order_ideal(self.to_poset().random_order_ideal()) @@ -1859,7 +1859,7 @@ def random_element(self) -> PP: EXAMPLES:: sage: PP = PlanePartitions([3,3,2], symmetry='SPP') - sage: PP.random_element() + sage: PP.random_element() # random Plane partition [[2, 2, 2], [2, 2], [2]] """ Z = self.from_order_ideal(self.to_poset().random_order_ideal()) @@ -2026,7 +2026,7 @@ def random_element(self) -> PP: EXAMPLES:: sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') - sage: PP.random_element() + sage: PP.random_element() # random Plane partition [[3, 2, 2], [3, 1], [1, 1]] """ Z = self.from_order_ideal(self.to_poset().random_order_ideal()) From 4cd3bfd58ea805c8181ed40116f73a9cade64f9e Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 11:15:41 -0500 Subject: [PATCH 57/74] small typo --- src/sage/combinat/plane_partition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index fb307f6c4b6..5791621728a 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1129,7 +1129,7 @@ class PlanePartitions(UniqueRepresentation, Parent): If no arguments are passed, then the class of all plane partitions is returned:: sage: PlanePartitions() - Plane Partitions + Plane partitions sage: [[2,1],[1]] in PlanePartitions() True From ae91118dfde36350a7451db7a2f68019650bfa39 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 12:10:48 -0500 Subject: [PATCH 58/74] Changed pp_all category to sets instead of enumerated sets --- src/sage/combinat/plane_partition.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 5791621728a..c9cde6187a1 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -42,6 +42,7 @@ from sage.combinat.tableau import Tableau from sage.arith.misc import Sigma from sage.functions.other import floor, ceil, binomial, factorial +from sage.categories.sets_cat import Sets @@ -1299,7 +1300,8 @@ def __init__(self): """ self._box = None self._symmetry = None - super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) + #super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) + super(PlanePartitions_all, self).__init__(category=Sets()) def _repr_(self) -> str: """ @@ -1312,6 +1314,18 @@ def _repr_(self) -> str: """ return "Plane partitions" + def an_element(self): + r""" + Return a particular element of the class. + + TESTS:: + + sage: P = PlanePartitions() + sage: P.an_element() + Plane partition [[2, 1], [1]] + """ + return self.element_class(self, [[2, 1], [1]]) + From 24471d0a06d41d0bd2c2e2d93fb44a9471f4b061 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 12:42:55 -0500 Subject: [PATCH 59/74] more disjoint union fixes --- src/sage/combinat/plane_partition.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index c9cde6187a1..970cc8f2cdf 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -43,7 +43,9 @@ from sage.arith.misc import Sigma from sage.functions.other import floor, ceil, binomial, factorial from sage.categories.sets_cat import Sets - +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.sets.family import Family +from sage.sets.non_negative_integers import NonNegativeIntegers PP = NewType('PP', 'PlanePartition') @@ -1272,7 +1274,7 @@ def __contains__(self, pp): -class PlanePartitions_all(PlanePartitions): +class PlanePartitions_all(PlanePartitions, DisjointUnionEnumeratedSets): r""" All plane partitions. @@ -1301,7 +1303,13 @@ def __init__(self): self._box = None self._symmetry = None #super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) - super(PlanePartitions_all, self).__init__(category=Sets()) + #super(PlanePartitions_all, self).__init__(category=Sets()) + + def PP_n(n): + return PlanePartitions_n(n) + DisjointUnionEnumeratedSets.__init__(self, + Family(NonNegativeIntegers(), PP_n), + facade=True, keepkey=False) def _repr_(self) -> str: """ @@ -1328,7 +1336,6 @@ def an_element(self): - class PlanePartitions_box(PlanePartitions): r""" All plane partitions that fit inside a box of a specified size. From c3f9ede39855bcb78ecf3e2205f80a50440a9d02 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 13:14:54 -0500 Subject: [PATCH 60/74] cleaning up patchbot complaints --- src/sage/combinat/plane_partition.py | 105 +++++++++++---------------- 1 file changed, 44 insertions(+), 61 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 970cc8f2cdf..ccf2456ae0a 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -26,7 +26,7 @@ # **************************************************************************** from typing import NewType, Iterator, Tuple -from sage.structure.list_clone import ClonableList, ClonableArray +from sage.structure.list_clone import ClonableList from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.richcmp import richcmp, richcmp_method from sage.structure.unique_representation import UniqueRepresentation @@ -35,7 +35,6 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset from sage.combinat.posets.poset_examples import posets -from sage.categories.cartesian_product import cartesian_product from sage.rings.integer import Integer from sage.rings.all import ZZ from sage.misc.all import prod @@ -154,7 +153,7 @@ def __richcmp__(self, other, op): .. TODO:: This overwrites the comparison check of - :class:`~sage.structure.list_clone.ClonableArray` + :class:`~sage.structure.list_clone.ClonableList` in order to circumvent the coercion framework. Eventually this should be solved more elegantly, for example along the lines of what was done for @@ -759,7 +758,7 @@ def transpose(self, tableau_only=False) -> PP: T[c][r] = z_tab[r][c] if tableau_only: return T - elif self.parent()._box == None or self.parent()._box[0] == self.parent()._box[1]: + elif self.parent()._box is None or self.parent()._box[0] == self.parent()._box[1]: return type(self)(self.parent(), T, check=False) new_box = (self.parent()._box[1],self.parent()._box[0],self.parent()._box[2]) return PlanePartitions(new_box,symmetry=self.parent._symmetry) @@ -1065,7 +1064,7 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) # Start code for determining correct parent - if self.parent()._box == None or preserve_parent == True or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): + if self.parent()._box is None or preserve_parent == True or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): return type(self)(self.parent(), ppMatrix, check=False) new_box = (self.parent()._box[2],self.parent()._box[0],self.parent()._box[1]) return PlanePartitions(new_box,symmetry=self.parent()._symmetry)(ppMatrix) @@ -1211,7 +1210,7 @@ def __classcall_private__(cls, *args, **kwds): return PlanePartitions_n(args[0]) else: box_size = args[0] - if symmetry == None: + if symmetry is None: return PlanePartitions_box(box_size) elif symmetry == 'SPP': return PlanePartitions_SPP(box_size) @@ -1388,6 +1387,18 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __contains__(self, x): + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2]) + True + sage: [[3,1],[1]] in PlanePartitions([2,2,2]) + False + sage: [[2,1],[1],[1]] in PlanePartitions([2,2,2]) + False + sage: [[2,1,1],[1]] in PlanePartitions([2,2,2]) + False + """ if len(x) == 0: return True return PlanePartitions.__contains__(self, x) and len(x) <= self._box[0] and len(x[0]) <= self._box[1] and x[0][0] <= self._box[2] @@ -1756,8 +1767,7 @@ def to_poset(self): sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ - a=self._box[0] - b=self._box[1] + a=self._box[0] c=self._box[2] pl = [] cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) @@ -1796,7 +1806,6 @@ def from_antichain(self, A) -> PP: #Initialize an empty plane partition a=self._box[0] b=self._box[1] - c=self._box[2] ppMatrix = [[0] * (b) for i in range(a)] #Antichain indicates where the 'corners' will be in the #plane partition @@ -1963,15 +1972,15 @@ def to_poset(self): a=self._box[0] b=self._box[1] c=self._box[2] - cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) - cmp2 = lambda x,y : cmp(x,y) or cmp(x,(y[2],y[0],y[1])) or cmp(x,(y[1],y[2],y[0])) + comp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) + comp2 = lambda x,y : comp(x,y) or comp(x,(y[2],y[0],y[1])) or comp(x,(y[1],y[2],y[0])) pl = [] for x in range(0,a): for y in range(0, b): for z in range(x,c): if y <= z and (x != z or y == x): pl.append((x,y,z)) - return Poset((pl, cmp2)) + return Poset((pl, comp2)) def from_antichain(self, acl) -> PP: r""" @@ -1985,7 +1994,6 @@ def from_antichain(self, acl) -> PP: sage: PP.from_antichain(A) Plane partition [[3, 3, 3], [3, 2, 1], [3, 1, 1]] """ - a=self._box[0] b=self._box[1] c=self._box[2] ppMatrix = [[0] * (c) for i in range(b)] @@ -2087,16 +2095,14 @@ def cardinality(self) -> Integer: sage: P.cardinality() 132 """ - A = self._box[0] - B = self._box[1] - C = self._box[2] + 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, 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, 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) @@ -2201,7 +2207,6 @@ def from_antichain(self, acl) -> PP: sage: PP.from_antichain(A) Plane partition [[3, 2, 1], [2, 1], [1]] """ - a=self._box[0] b=self._box[1] c=self._box[2] ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane @@ -2288,10 +2293,8 @@ def cardinality(self) -> Integer: sage: P.cardinality() 66 """ - A = self._box[0] - B = self._box[1] - C = self._box[2] - 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) )) + 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) )) @@ -2619,12 +2622,8 @@ def cardinality(self) -> Integer: """ a=self._box[0] - b=self._box[1] c=self._box[2] - if a==b and c % 2 == 0: - 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))) - else: - return Integer(0) + 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))) #Class 7 @@ -2663,8 +2662,8 @@ def __init__(self, box_size): if box_size[0]!=box_size[1]: raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) - if (box_size[0] % 2 == 1 or box_size[1] % 2 == 1 or box_size[2] % 2 == 1): - raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) + if (box_size[2] % 2 == 1): + raise ValueError("z dimension ({}) must be even".format(box_size[0])) super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SSCPP' @@ -2721,22 +2720,17 @@ def cardinality(self) -> Integer: sage: P = PlanePartitions([4,4,2], symmetry='SSCPP') sage: P.cardinality() 6 + sage: Q = PlanePartitions([3,3,2], symmetry='SSCPP') + 3 + """ - r=self._box[0] - s=self._box[1] - t=self._box[2] - if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) - for i in range(1,1+r/2) - for j in range(1,1+r/2) - for k in range(1,1+t/2)))) - if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) - for i in range(1,1+(r-1)/2) - for j in range(1,1+((r-1)/2)+1) - for k in range(1,1+t/2)))) - return Integer(0) + 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+floor(a/2)) + for j in range(1,1+ceil(a/2)) + for k in range(1,1+c/2)))) #Class 8 @@ -2821,11 +2815,8 @@ def cardinality(self) -> Integer: 11 """ a=self._box[0] - b=self._box[1] - c=self._box[2] - if a == b and b == c and a % 2 == 0: - return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range((a/2)))) - return Integer(0) + return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range((a/2)))) + # Class 9 @@ -2911,11 +2902,7 @@ def cardinality(self) -> Integer: 49 """ a=self._box[0] - b=self._box[1] - c=self._box[2] - if a == b and b == c and a % 2 == 0: - return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) - return Integer(0) + return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) @@ -3147,10 +3134,6 @@ def cardinality(self) -> Integer: 7 """ a=self._box[0] - b=self._box[1] - c=self._box[2] - if a == b and b == c and a % 2 == 0: - return Integer(prod( ((factorial(3*i+1)/(factorial(a/2+i)) for i in range((a/2)))))) - return Integer(0) + return Integer(prod( ((factorial(3*i+1)/(factorial(a/2+i)) for i in range((a/2)))))) From a5d6a11fc8dc0b466e9123beda30e11e1fc96784 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 13:34:45 -0500 Subject: [PATCH 61/74] final touchups --- src/sage/combinat/plane_partition.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index ccf2456ae0a..c6c325b10bf 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -2656,14 +2656,14 @@ def __init__(self, box_size): sage: PlanePartitions([4,4,3], symmetry='SSCPP') Traceback (most recent call last): ... - ValueError: x, y, and z dimensions (4,4,3) must all be even + ValueError: z dimension (3) must be even """ if box_size[0]!=box_size[1]: raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) if (box_size[2] % 2 == 1): - raise ValueError("z dimension ({}) must be even".format(box_size[0])) + raise ValueError("z dimension ({}) must be even".format(box_size[2])) super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) self._box = box_size self._symmetry = 'SSCPP' @@ -2721,6 +2721,7 @@ def cardinality(self) -> Integer: sage: P.cardinality() 6 sage: Q = PlanePartitions([3,3,2], symmetry='SSCPP') + sage: Q.cardinality() 3 From 2e2996ee96eb2ec258ba71913373c8ba2b60fe9c Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 2 Sep 2021 15:08:58 -0500 Subject: [PATCH 62/74] Addressing more patchbot complaints --- src/sage/combinat/plane_partition.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index c6c325b10bf..5cfa2502b8b 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -32,7 +32,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.posets.posets import Poset from sage.combinat.posets.poset_examples import posets from sage.rings.integer import Integer @@ -41,7 +40,6 @@ from sage.combinat.tableau import Tableau from sage.arith.misc import Sigma from sage.functions.other import floor, ceil, binomial, factorial -from sage.categories.sets_cat import Sets from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers @@ -1039,7 +1037,8 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: sage: PP_rotated in PP_rotated.parent() False """ - (a, b, c) = (self._max_x, self._max_y, self._max_z) + b = self._max_y + c = self._max_z new_antichain = [] for elem in self.maximal_boxes(): new = (elem[1], elem[2], elem[0]) @@ -1064,7 +1063,7 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) # Start code for determining correct parent - if self.parent()._box is None or preserve_parent == True or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): + if self.parent()._box is None or preserve_parent or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): return type(self)(self.parent(), ppMatrix, check=False) new_box = (self.parent()._box[2],self.parent()._box[0],self.parent()._box[1]) return PlanePartitions(new_box,symmetry=self.parent()._symmetry)(ppMatrix) @@ -1444,7 +1443,6 @@ def from_antichain(self, A) -> PP: """ a = self._box[0] b = self._box[1] - c = self._box[2] ppMatrix = [[0] * (b) for i in range(a)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] #ac format ex: [x,y,z] @@ -1756,7 +1754,7 @@ def __contains__(self, x) -> bool: def to_poset(self): r""" - Returns a poset whose order ideals are in bijection with + Return a poset whose order ideals are in bijection with symmetric plane partitions. EXAMPLES:: @@ -1866,12 +1864,11 @@ def cardinality(self) -> Integer: sage: P.cardinality() 35 """ - A = self._box[0] - B = self._box[1] - C = self._box[2] - leftProduct = (prod( (2*i + C - 1) / (2*i - 1) for i in range(1,A+1))) - rightProduct = (prod( (i + j + C - 1) / (i + j - 1) - for j in range(1, A+1) + a = self._box[0] + c = self._box[2] + leftProduct = (prod( (2*i + c - 1) / (2*i - 1) for i in range(1,a+1))) + rightProduct = (prod( (i + j + c - 1) / (i + j - 1) + for j in range(1, a+1) for i in range(1, j) )) return Integer(leftProduct * rightProduct) @@ -2173,7 +2170,7 @@ def __contains__(self, x) -> bool: def to_poset(self): r""" - Returns a poset whose order ideals are in bijection with totally + Return a poset whose order ideals are in bijection with totally symmetric plane partitions. EXAMPLES:: @@ -2960,7 +2957,7 @@ def _repr_(self) -> str: def to_poset(self): r""" - Returns a poset whose order ideals are in bijection with + Return a poset whose order ideals are in bijection with totally symmetric self-complementary plane partitions. EXAMPLES:: From 6c697302955a1cb082ec48541918e09f706d7db7 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 14 Sep 2021 09:24:16 -0500 Subject: [PATCH 63/74] removed comment from all.py, clonablelist to cloneablearray --- src/sage/combinat/all.py | 3 --- src/sage/combinat/plane_partition.py | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index dd1b5f0d70e..2581de72b91 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -136,9 +136,6 @@ # Plane Partitions lazy_import('sage.combinat.plane_partition', ('PlanePartition', 'PlanePartitions')) - -#from .plane_partition import PlanePartition, PlanePartitions - # Parking Functions lazy_import('sage.combinat.non_decreasing_parking_function', ['NonDecreasingParkingFunctions', 'NonDecreasingParkingFunction']) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 5cfa2502b8b..6c4f3224142 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -26,7 +26,7 @@ # **************************************************************************** from typing import NewType, Iterator, Tuple -from sage.structure.list_clone import ClonableList +from sage.structure.list_clone import ClonableArray from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.richcmp import richcmp, richcmp_method from sage.structure.unique_representation import UniqueRepresentation @@ -50,7 +50,7 @@ @richcmp_method -class PlanePartition(ClonableList, metaclass=InheritComparisonClasscallMetaclass): +class PlanePartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A plane partition. @@ -122,7 +122,7 @@ def __init__(self, parent, pp, check=True): """ if isinstance(pp, PlanePartition): - ClonableList.__init__(self, parent, pp, check=False) + ClonableArray.__init__(self, parent, pp, check=False) else: pp = [list(_) for _ in pp] if pp: @@ -131,7 +131,7 @@ def __init__(self, parent, pp, check=True): del pp[i][-1] if not pp[i]: pp.pop(i) - ClonableList.__init__(self, parent, pp, check=check) + ClonableArray.__init__(self, parent, pp, check=check) if self.parent()._box is None: if pp: self._max_x = len(pp) @@ -151,7 +151,7 @@ def __richcmp__(self, other, op): .. TODO:: This overwrites the comparison check of - :class:`~sage.structure.list_clone.ClonableList` + :class:`~sage.structure.list_clone.ClonableArray` in order to circumvent the coercion framework. Eventually this should be solved more elegantly, for example along the lines of what was done for From 97320c028deb2cac6e48fc25e2d5d96959ef3b6b Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 14 Sep 2021 09:58:28 -0500 Subject: [PATCH 64/74] deleted extraneously lines and minor doc changes --- src/sage/combinat/plane_partition.py | 168 ++++++++------------------- 1 file changed, 49 insertions(+), 119 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 6c4f3224142..268f9a8b829 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -25,7 +25,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from typing import NewType, Iterator, Tuple - from sage.structure.list_clone import ClonableArray from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.richcmp import richcmp, richcmp_method @@ -44,11 +43,8 @@ from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers - PP = NewType('PP', 'PlanePartition') - - @richcmp_method class PlanePartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" @@ -219,15 +215,15 @@ def check(self): """ if not all(all(a in ZZ for a in b) for b in self): - raise ValueError("Entries not all integers") + raise ValueError("entries not all integers") for row in self: if not all(c >= 0 for c in row): - raise ValueError("Entries not all nonnegative") + raise ValueError("entries not all nonnegative") if not all(row[i] >= row[i+1] for i in range(len(row)-1)): - raise ValueError("Not weakly decreasing along rows") + raise ValueError("not weakly decreasing along rows") for row, next in zip(self, self[1:]): if not all(row[c] >= next[c] for c in range(len(next))): - raise ValueError("Not weakly decreasing along columns") + raise ValueError("not weakly decreasing along columns") def _repr_(self) -> str: """ @@ -691,7 +687,6 @@ def contains(self, PP) -> bool: return False return all([self[i][j] >= PP[i][j] for j in range(len(PP[i])) for i in range(len(PP))]) - def complement(self, tableau_only=False) -> PP: r""" @@ -760,10 +755,6 @@ def transpose(self, tableau_only=False) -> PP: return type(self)(self.parent(), T, check=False) new_box = (self.parent()._box[1],self.parent()._box[0],self.parent()._box[2]) return PlanePartitions(new_box,symmetry=self.parent._symmetry) - # elif self._max_x != self._max_y: - # raise ValueError("Tranpose only supports parents with symmetric dimensions") - # else: - # return type(self)(self.parent(), T, check=False) def is_SPP(self) -> bool: r""" @@ -852,8 +843,6 @@ def is_SCPP(self) -> bool: contained in. If no parent/bounding box is specified, the box is taken to be the smallest box that contains the plane partition. - - EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -956,35 +945,33 @@ def is_TSSCPP(self) -> bool: """ return self.is_TSPP() and self.is_SCPP() -# def to_order_ideal(self): -# """ -# Return the order ideal corresponding to ``self``. - -# TODO: As many families of symmetric plane partitions are in bijection -# with order ideals in an associated poset, this function could -# feasibly have options to send symmetric plane partitions -# to the associated order ideal in that poset, instead. -# -# EXAMPLES:: -# -# sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() -# [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] -# sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() -# [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] -# """ -# (a, b, c) = (self._max_x, self._max_y, self._max_z) -# Q = posets.ProductOfChains([a,b,c]) -# count = 0 -# generate = [] -# for i in range(len(self)): -# for j in range(len(self[i])): -# if (self[i][j] > 0): -# generate.append((i,j,self[i][j]-1)) -# count += 1 -# oi = Q.order_ideal(generate) -# return oi - + def to_order_ideal(self): + """ + Return the order ideal corresponding to ``self``. + TODO: As many families of symmetric plane partitions are in bijection + with order ideals in an associated poset, this function could + feasibly have options to send symmetric plane partitions + to the associated order ideal in that poset, instead. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] + sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] + """ + (a, b, c) = (self._max_x, self._max_y, self._max_z) + Q = posets.ProductOfChains([a,b,c]) + count = 0 + generate = [] + for i in range(len(self)): + for j in range(len(self[i])): + if (self[i][j] > 0): + generate.append((i,j,self[i][j]-1)) + count += 1 + oi = Q.order_ideal(generate) + return oi def maximal_boxes(self) -> list: """ @@ -1067,7 +1054,6 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: return type(self)(self.parent(), ppMatrix, check=False) new_box = (self.parent()._box[2],self.parent()._box[0],self.parent()._box[1]) return PlanePartitions(new_box,symmetry=self.parent()._symmetry)(ppMatrix) - #return PlanePartition(ppMatrix) class PlanePartitions(UniqueRepresentation, Parent): r""" @@ -1232,10 +1218,8 @@ def __classcall_private__(cls, *args, **kwds): else: raise ValueError("invalid symmetry class option; must be None, 'SPP', 'CSPP', 'TSPP', 'SCPP', 'TCPP', 'SSCPP', 'CSTCPP', 'CSSCPP', or 'TSSCPP' ") - Element = PlanePartition - def __contains__(self, pp): """ Check to see that ``pp`` is a valid plane partition. @@ -1268,10 +1252,6 @@ def __contains__(self, pp): return True return False - - - - class PlanePartitions_all(PlanePartitions, DisjointUnionEnumeratedSets): r""" All plane partitions. @@ -1282,7 +1262,6 @@ class PlanePartitions_all(PlanePartitions, DisjointUnionEnumeratedSets): PlanePartitions(n) for n an integer. """ - def __init__(self): r""" Initializes the class of all plane partitions. @@ -1301,7 +1280,7 @@ def __init__(self): self._box = None self._symmetry = None #super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) - #super(PlanePartitions_all, self).__init__(category=Sets()) + super(PlanePartitions_all, self).__init__(category=Sets()) def PP_n(n): return PlanePartitions_n(n) @@ -1332,8 +1311,6 @@ def an_element(self): """ return self.element_class(self, [[2, 1], [1]]) - - class PlanePartitions_box(PlanePartitions): r""" All plane partitions that fit inside a box of a specified size. @@ -1370,7 +1347,6 @@ def __init__(self, box_size): self._box = box_size self._symmetry = None - def _repr_(self) -> str: """ @@ -1491,9 +1467,6 @@ def __iter__(self) -> Iterator: PP[A - 1 - r][B - 1 - c] = T[r][c] - r - 1 yield self.element_class(self, PP, check=False) - - - def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -1552,8 +1525,6 @@ def random_element(self) -> PP: Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) - - class PlanePartitions_n(PlanePartitions): """ Plane partitions with a fixed number of boxes. @@ -1684,17 +1655,13 @@ def cardinality(self) -> Integer: PPn.append(nextPPn) return(Integer(PPn[-1])) -#Symmetry classes are enumerated and labelled in order as in Proofs and -#Confirmations/Stanley (with all plane partitions being the first class) - - +# Symmetry classes are enumerated and labelled in order as in Proofs and +# Confirmations/Stanley (with all plane partitions being the first class) - -#Class 2 +# Class 2 +# Symmetric Plane Partitions class PlanePartitions_SPP(PlanePartitions): - - @staticmethod def __classcall_private__(cls, box_size): """ @@ -1751,7 +1718,6 @@ def __contains__(self, x) -> bool: max = (P._max_x, P._max_y, P._max_z) return PlanePartitions.__contains__(self, x) and P.is_SPP() and all( a<=b for a,b in zip(max,self._box)) - def to_poset(self): r""" Return a poset whose order ideals are in bijection with @@ -1892,11 +1858,10 @@ def random_element(self) -> PP: Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) -#Class 3 +# Class 3 +# Cyclically Symmetric Plane Partitions class PlanePartitions_CSPP(PlanePartitions): - - @staticmethod def __classcall_private__(cls, box_size): """ @@ -2005,7 +1970,6 @@ def from_antichain(self, acl) -> PP: ppMatrix[z][x] = (y+1) ppMatrix[x][y] = (z+1) - #for each value in current antichain, fill in the rest of the #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is #now in plane partition format @@ -2103,15 +2067,10 @@ def cardinality(self) -> Integer: for i in range(1,j+1)) return Integer(numerator/denominator) - # Class 4 - +# Totally Symmetric Plane Partitions class PlanePartitions_TSPP(PlanePartitions): -# Totally symmetric plane partitions - -# Make sure inputs checked, code doesn't have a,b,c treated properly - @staticmethod def __classcall_private__(cls, box_size): """ @@ -2213,7 +2172,6 @@ def from_antichain(self, acl) -> PP: y = ac[1] z = ac[2] - ppMatrix[y][z] = (x+1) #x,y,z ppMatrix[z][x] = (y+1) #y,z,x ppMatrix[x][y] = (z+1) #z,x,y @@ -2222,7 +2180,6 @@ def from_antichain(self, acl) -> PP: ppMatrix[x][z] = (y+1) #y,x,z ppMatrix[y][x] = (z+1) #z,y,x - #for each value in current antichain, fill in the rest of the matrix by #rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format if acl != []: @@ -2254,8 +2211,6 @@ def from_order_ideal(self, I) -> PP: """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) - - def __iter__(self) -> Iterator: """ An iterator for totally symmetric plane partitions. @@ -2272,7 +2227,6 @@ def __iter__(self) -> Iterator: for A in self.to_poset().antichains_iterator(): yield self.from_antichain(A) - def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -2293,12 +2247,10 @@ def cardinality(self) -> Integer: 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) )) - - # Class 5 +# Self-complementary Plane Partitions class PlanePartitions_SCPP(PlanePartitions): -# Self-complementary plane partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -2416,7 +2368,6 @@ def possible_middle_row_for_b_odd(a,c): def possible_middle_row_for_b_even(a,c): "Returns the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" -# for mu in Partitions_inside_lambda([floor(c/2) for i in range((a+1)/2)]): for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor((a+1)/2))]): nu = [c-mu[len(mu)-1-i] for i in range(floor(a/2))] for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu,mu[0]): @@ -2424,8 +2375,6 @@ def possible_middle_row_for_b_even(a,c): yield (la) return - - def PPs_with_first_row_la_and_with_k_rows(la,k): "Returns PPs with first row la and with k rows in total" if k == 0: @@ -2437,7 +2386,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): @@ -2448,9 +2396,6 @@ def complement(PP,c): a = len(PP[0]) return [[c-PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] - if a*b*c % 2 == 1: - return - if b % 2 == 1: for la in possible_middle_row_for_b_odd(a,c): # la is the middle row of SCPP for PP in PPs_with_first_row_la_and_with_k_rows(la,(b+1)/2): @@ -2476,8 +2421,6 @@ def cardinality(self) -> Integer: \left(\prod_{i=1}^{r}\prod_{j=1}^{b} \frac{i + j + c - 1}{i + j - 1}\right)^2 - - The number of self complementary plane partitions inside an `(2a+1) \times 2b \times 2c` box is equal to @@ -2529,8 +2472,8 @@ def cardinality(self) -> Integer: if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: return Integer(0) - -#Class 6 +# Class 6 +# Transpose-complement Plane Partitions class PlanePartitions_TCPP(PlanePartitions): @staticmethod @@ -2598,8 +2541,6 @@ def __iter__(self) -> Iterator: yield self.element_class(self,p) return - - def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -2622,10 +2563,10 @@ def cardinality(self) -> Integer: 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,1+a-2) for i in range(1,1+j))) -#Class 7 +# Class 7 +# Symmetric Self-complementary Plane Partitions class PlanePartitions_SSCPP(PlanePartitions): -#Symmetric self-complementary plane partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -2655,8 +2596,6 @@ def __init__(self, box_size): ... ValueError: z dimension (3) must be even """ - - if box_size[0]!=box_size[1]: raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) if (box_size[2] % 2 == 1): @@ -2730,10 +2669,10 @@ def cardinality(self) -> Integer: for j in range(1,1+ceil(a/2)) for k in range(1,1+c/2)))) -#Class 8 +# Class 8 +#Cyclically Symmetric Transpose-complement Partitions class PlanePartitions_CSTCPP(PlanePartitions): -#Cyclically symmetric transpose complement partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -2815,12 +2754,11 @@ def cardinality(self) -> Integer: a=self._box[0] return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range((a/2)))) - # Class 9 - +# Cyclically Symmetric Self-complementary Plane Partitions class PlanePartitions_CSSCPP(PlanePartitions): -# Cyclically symmetric self-complementary plane partitions + @staticmethod def __classcall_private__(cls, box_size): """ @@ -2902,12 +2840,10 @@ def cardinality(self) -> Integer: a=self._box[0] return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) - - -#Class 10 +# Class 10 +#Totally Symmetric Self-complementary Plane Partitions class PlanePartitions_TSSCPP(PlanePartitions): -#Totally symmetric self-complementary plane partitions @staticmethod def __classcall_private__(cls, box_size): """ @@ -3040,7 +2976,6 @@ def from_antichain(self, acl) -> PP: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) - #fill half of triangle symmetrically for i in range(width): i = i + n/2 @@ -3054,7 +2989,6 @@ def from_antichain(self, acl) -> PP: for j in range(n/2): ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] - #fill in lower left cube with values n/2 for i in range(n/2): for j in range(n/2): @@ -3065,7 +2999,6 @@ def from_antichain(self, acl) -> PP: if(ppMatrix[x+(n/2)][y]) == 0: ppMatrix[x+(n/2)][y] = n/2 - #add and subtract values from lower left cube to be rotation of lower right cube for i in range(n/2): for j in range(n/2): @@ -3099,7 +3032,6 @@ def from_order_ideal(self, I) -> PP: """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) - def __iter__(self) -> Iterator: """ An iterator for totally symmetric self-complementary plane partitions. @@ -3133,5 +3065,3 @@ def cardinality(self) -> Integer: """ a=self._box[0] return Integer(prod( ((factorial(3*i+1)/(factorial(a/2+i)) for i in range((a/2)))))) - - From 5cb32b6266175dc4659e74e412d1a0d1e32c330b Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 14 Sep 2021 10:19:39 -0500 Subject: [PATCH 65/74] trailing whitespace removal --- src/sage/combinat/plane_partition.py | 123 ++++++++++++++------------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 268f9a8b829..cd5310c9f27 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -663,9 +663,9 @@ def contains(self, PP) -> bool: Specifically, ``self`` contains ``PP`` if, for all `i`, `j`, the height of ``PP`` at `ij` is less than or equal to the height of ``self`` at `ij`. - + EXAMPLES:: - + sage: P1 = PlanePartition([[5,4,3],[3,2,2],[1]]) sage: P2 = PlanePartition([[3,2],[1,1],[0,0],[0,0]]) sage: P3 = PlanePartition([[5,5,5],[2,1,0]]) @@ -681,7 +681,7 @@ def contains(self, PP) -> bool: PP = PlanePartition(PP) if len(self) < len(PP): return False - + for i in range(len(PP)): if len(self[i]) < len(PP[i]): return False @@ -953,9 +953,9 @@ def to_order_ideal(self): with order ideals in an associated poset, this function could feasibly have options to send symmetric plane partitions to the associated order ideal in that poset, instead. - + EXAMPLES:: - + sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() @@ -976,9 +976,9 @@ def to_order_ideal(self): def maximal_boxes(self) -> list: """ Return the coordinates of the maximal boxes of ``self``. - + EXAMPLES:: - + sage: sorted(PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes()) [[0, 0, 2], [0, 2, 0], [1, 1, 1], [2, 0, 1]] sage: sorted(PlanePartition([[2,1],[1],[1]]).maximal_boxes()) @@ -995,7 +995,7 @@ def maximal_boxes(self) -> list: count+=1 oi = Q.order_ideal_generators(generate) return [list(oi_elem) for oi_elem in oi] - + def cyclically_rotate(self, preserve_parent=False) -> PP: r""" Return the cyclic rotation of ``self``. @@ -1004,11 +1004,11 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: partitions inside an `a \times b \times c` box, the result will have a parent consisting of partitions inside a `c \times a \times b` box, unless the optional parameter - ``preserve_parents`` is set to ``True``. Enabling this setting + ``preserve_parent`` is set to ``True``. Enabling this setting may give an element that is NOT an element of its parent. - + EXAMPLES:: - + sage: PlanePartition([[3,2,1],[2,2],[2]]).cyclically_rotate() Plane partition [[3, 3, 1], [2, 2], [1]] sage: PP = PlanePartition([[4,1],[1],[1]]) @@ -1112,7 +1112,7 @@ class PlanePartitions(UniqueRepresentation, Parent): and at least one of `a,b,c` be even. EXAMPLES: - + If no arguments are passed, then the class of all plane partitions is returned:: sage: PlanePartitions() @@ -1226,11 +1226,11 @@ def __contains__(self, pp): EXAMPLES:: - sage: [[3,2,1],[2,1]] in PlanePartitions() + sage: [[3,2,1],[2,1]] in PlanePartitions() True - sage: [[3,2,1],[1,2]] in PlanePartitions() + sage: [[3,2,1],[1,2]] in PlanePartitions() False - sage: [[3,2,1],[3,3]] in PlanePartitions() + sage: [[3,2,1],[3,3]] in PlanePartitions() False """ @@ -1414,7 +1414,7 @@ def from_antichain(self, A) -> PP: EXAMPLES:: sage: A = [(1,0,1), (0,1,1), (1,1,0)] - sage: PlanePartitions([2,2,2]).from_antichain(A) + sage: PlanePartitions([2,2,2]).from_antichain(A) Plane partition [[2, 2], [2, 1]] """ a = self._box[0] @@ -1430,7 +1430,7 @@ def from_antichain(self, A) -> PP: ppMatrix[x][y] = (z+1) #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format - if A != []: + if not A: for i in range(a): i = a-(i+1) for j in range(b): @@ -1581,21 +1581,6 @@ def __iter__(self) -> Iterator: [Plane partition [[2]], Plane partition [[1, 1]], Plane partition [[1], [1]]] """ from sage.combinat.partition import Partitions - def PP_first_row_iter(n, la): - m = n-sum(la) - if m < 0: - yield - return - if m==0: - yield [la] - return - for k in range(m,0,-1): - for mu in P_in_shape_iter(k,la): - if mu is not None: - for PP in PP_first_row_iter(m, mu): - if PP is not None: - yield [la] + PP - def P_in_shape_iter(n, la): if n<0 or sum(la) PP: sage: PP = PlanePartitions([3,3,2], symmetry='SPP') sage: I = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (2, 0, 0)] - sage: PP.from_order_ideal(I) + sage: PP.from_order_ideal(I) Plane partition [[1, 1, 1], [1, 1], [1]] """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) @@ -1764,7 +1765,7 @@ def from_antichain(self, A) -> PP: sage: PP = PlanePartitions([3,3,2], symmetry='SPP') sage: A = [(2, 2, 0), (1, 0, 1), (1, 1, 0)] - sage: PP.from_antichain(A) + sage: PP.from_antichain(A) Plane partition [[2, 2, 1], [2, 1, 1], [1, 1, 1]] """ #Initialize an empty plane partition @@ -1780,7 +1781,7 @@ def from_antichain(self, A) -> PP: ppMatrix[x][y] = (z+1) #Fill out the rest of the plane partition using symmetry and the #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) - if A!= []: + if not A: for i in range(a): i = a-(i+1) for j in range(b): @@ -1925,10 +1926,10 @@ def to_poset(self): EXAMPLES:: - sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') - sage: PP.to_poset() + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: PP.to_poset() Finite poset containing 11 elements - sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ a=self._box[0] @@ -1953,7 +1954,7 @@ def from_antichain(self, acl) -> PP: sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') sage: A = [(0, 2, 2), (1, 1, 1)] - sage: PP.from_antichain(A) + sage: PP.from_antichain(A) Plane partition [[3, 3, 3], [3, 2, 1], [3, 1, 1]] """ b=self._box[1] @@ -1997,7 +1998,7 @@ def from_order_ideal(self, I) -> PP: sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), (1, 0, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2)] - sage: PP.from_order_ideal(I) + sage: PP.from_order_ideal(I) Plane partition [[3, 3, 3], [3, 3, 3], [3, 3, 2]] """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) @@ -2088,7 +2089,7 @@ def __classcall_private__(cls, box_size): def __init__(self, box_size): """ TESTS:: - + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') sage: TestSuite(PP).run() sage: PlanePartitions([4,3,2], symmetry='TSPP') @@ -2134,10 +2135,10 @@ def to_poset(self): EXAMPLES:: - sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') - sage: PP.to_poset() + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: PP.to_poset() Finite poset containing 10 elements - sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ a=self._box[0] @@ -2160,7 +2161,7 @@ def from_antichain(self, acl) -> PP: sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') sage: A = [(0, 0, 2), (0, 1, 1)] - sage: PP.from_antichain(A) + sage: PP.from_antichain(A) Plane partition [[3, 2, 1], [2, 1], [1]] """ b=self._box[1] @@ -2206,7 +2207,7 @@ def from_order_ideal(self, I) -> PP: sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1)] - sage: PP.from_order_ideal(I) + sage: PP.from_order_ideal(I) Plane partition [[3, 2, 1], [2, 1], [1]] """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) @@ -2268,7 +2269,7 @@ def __classcall_private__(cls, box_size): def __init__(self, box_size): """ TESTS:: - + sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') sage: TestSuite(PP).run() sage: PlanePartitions([5,3,1], symmetry='SCPP') @@ -2584,7 +2585,7 @@ def __classcall_private__(cls, box_size): def __init__(self, box_size): """ TESTS:: - + sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') sage: TestSuite(PP).run() sage: PlanePartitions([4,2,2], symmetry='SSCPP') @@ -2690,7 +2691,7 @@ def __classcall_private__(cls, box_size): def __init__(self, box_size): """ TESTS:: - + sage: PP = PlanePartitions([2,2,2], symmetry='CSTCPP') sage: TestSuite(PP).run() sage: PlanePartitions([4,3,2], symmetry='CSTCPP') @@ -2841,7 +2842,7 @@ def cardinality(self) -> Integer: return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) # Class 10 -#Totally Symmetric Self-complementary Plane Partitions +# Totally Symmetric Self-complementary Plane Partitions class PlanePartitions_TSSCPP(PlanePartitions): @staticmethod @@ -2861,7 +2862,7 @@ def __classcall_private__(cls, box_size): def __init__(self, box_size): """ TESTS:: - + sage: PP = PlanePartitions([4,4,4], symmetry='TSSCPP') sage: TestSuite(PP).run() sage: PlanePartitions([4,3,2], symmetry='TSSCPP') @@ -2898,10 +2899,10 @@ def to_poset(self): EXAMPLES:: - sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') - sage: PP.to_poset() + sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: PP.to_poset() Finite poset containing 4 elements - sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) @@ -2934,7 +2935,7 @@ def from_antichain(self, acl) -> PP: sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') sage: A = [(0, 0, 1), (1, 1, 0)] - sage: PP.from_antichain(A) + sage: PP.from_antichain(A) Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 4, 3, 1], [6, 5, 4, 3, 2, 1], [5, 4, 3, 2, 1], [5, 3, 2, 1, 1], [3, 1, 1]] """ #ac format ex: [x,y,z] @@ -3017,7 +3018,7 @@ def from_antichain(self, acl) -> PP: for j in range(n/2): ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] return self.element_class(self, ppMatrix) - + def from_order_ideal(self, I) -> PP: r""" Return the totally symmetric self-complementary plane partition corresponding @@ -3027,7 +3028,7 @@ def from_order_ideal(self, I) -> PP: sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') sage: I = [(0, 0, 0), (0, 1, 0), (1, 1, 0)] - sage: PP.from_order_ideal(I) + sage: PP.from_order_ideal(I) Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 3, 3, 1], [6, 5, 5, 3, 3, 1], [5, 3, 3, 1, 1], [5, 3, 3, 1, 1], [3, 1, 1]] """ return self.from_antichain(self.to_poset().order_ideal_generators(I)) From 796ec58b3f8b9c3166abe62f0ad8695c27fc77f7 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 14 Sep 2021 11:03:43 -0500 Subject: [PATCH 66/74] checkpoint --- src/sage/combinat/plane_partition.py | 160 +++++++++++++-------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index cd5310c9f27..de0df50c671 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -42,6 +42,7 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.categories.sets_cat import Sets PP = NewType('PP', 'PlanePartition') @@ -199,19 +200,19 @@ def check(self): sage: b = PlanePartition([[1,2],[1]]) Traceback (most recent call last): ... - ValueError: Not weakly decreasing along rows + ValueError: not weakly decreasing along rows sage: c = PlanePartition([[1,1],[2]]) Traceback (most recent call last): ... - ValueError: Not weakly decreasing along columns + ValueError: not weakly decreasing along columns sage: d = PlanePartition([[2,-1],[-2]]) Traceback (most recent call last): ... - ValueError: Entries not all nonnegative + ValueError: entries not all nonnegative sage: e = PlanePartition([[3/2,1],[.5]]) Traceback (most recent call last): ... - ValueError: Entries not all integers + ValueError: entries not all integers """ if not all(all(a in ZZ for a in b) for b in self): @@ -977,6 +978,9 @@ def maximal_boxes(self) -> list: """ Return the coordinates of the maximal boxes of ``self``. + The maximal boxes of a plane partitions are the boxes that can be + removed from a plane partition and still yield a valid plane partition. + EXAMPLES:: sage: sorted(PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes()) @@ -992,7 +996,7 @@ def maximal_boxes(self) -> list: for j in range(len(self[i])): if (self[i][j] > 0): generate.append((i,j,self[i][j]-1)) - count+=1 + count += 1 oi = Q.order_ideal_generators(generate) return [list(oi_elem) for oi_elem in oi] @@ -1070,43 +1074,43 @@ class PlanePartitions(UniqueRepresentation, Parent): plane partitions inside a box of the specified size satisfying certain symmetry conditions. - - ``symmetry='SPP'`` gives the class of symmetric plane partitions. which + - ``symmetry = 'SPP'`` gives the class of symmetric plane partitions. which is all plane partitions fixed under reflection across the diagonal. Requires that `a = b`. - - ``symmetry='CSPP'`` gives the class of cyclic plane partitions, which + - ``symmetry = 'CSPP'`` gives the class of cyclic plane partitions, which is all plane partitions fixed under cyclic rotation of coordinates. Requires that `a = b = c`. - - ``symmetry='TSPP'`` gives the class of totally symmetric plane partitions, + - ``symmetry = 'TSPP'`` gives the class of totally symmetric plane partitions, which is all plane partitions fixed under any interchanging of coordinates. Requires that `a = b = c`. - - ``symmetry='SCPP'`` gives the class of self-complementary plane partitions. + - ``symmetry = 'SCPP'`` gives the class of self-complementary plane partitions. which is all plane partitions that are equal to their own complement in the specified box. Requires at least one of `a,b,c` be even. - - ``symmetry='TCPP'`` gives the class of transpose complement plane partitions, + - ``symmetry = 'TCPP'`` gives the class of transpose complement plane partitions, which is all plane partitions whose complement in the box of the specified size is equal to their transpose. Requires `a = b` and at least one of `a,b,c` be even. - - ``symmetry='SSCPP'`` gives the class of symmetric self-complementary + - ``symmetry = 'SSCPP'`` gives the class of symmetric self-complementary plane partitions, which is all plane partitions that are both symmetric and self-complementary. Requires `a = b` and at least one of `a,b,c` be even. - - ``symmetry='CSTCPP'`` gives the class of cyclically symmetric transpose + - ``symmetry = 'CSTCPP'`` gives the class of cyclically symmetric transpose complement plane partitions, which is all plane partitions that are both symmetric and equal to the transpose of their complement. Requires `a = b = c`. - - ``symmetry='CSSCPP'`` gives the class of cyclically symmetric + - ``symmetry = 'CSSCPP'`` gives the class of cyclically symmetric self-complementary plane partitions, which is all plane partitions that are both cyclically symmetric and self-complementary. Requires `a = b = c` and at least one of `a,b,c` be even. - - ``symmetry='TSSCPP'`` gives the class of totally symmetric + - ``symmetry = 'TSSCPP'`` gives the class of totally symmetric self-complementary plane partitions, which is all plane partitions that are totally symmetric and also self-complementary. Requires `a = b = c` and at least one of `a,b,c` be even. @@ -1280,7 +1284,8 @@ def __init__(self): self._box = None self._symmetry = None #super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) - super(PlanePartitions_all, self).__init__(category=Sets()) + #super(PlanePartitions_all, self).__init__(category=Sets()) + #super(PlanePartitions_all, self).__init__(category=DisjointUnionEnumeratedSets()) def PP_n(n): return PlanePartitions_n(n) @@ -1388,9 +1393,9 @@ def to_poset(self): sage: PlanePartitions([2,2,2]).to_poset() Finite lattice containing 8 elements """ - a=self._box[0] - b=self._box[1] - c=self._box[2] + a = self._box[0] + b = self._box[1] + c = self._box[2] return posets.ProductOfChains([a,b,c]) def from_order_ideal(self, I) -> PP: @@ -1583,20 +1588,20 @@ def __iter__(self) -> Iterator: from sage.combinat.partition import Partitions def P_in_shape_iter(n, la): - if n<0 or sum(la)=n: + if len(la) == 1: + if la[0] >= n: yield [n] return else: yield return - if sum(la)==n: + if sum(la) == n: yield la return for mu_0 in range(min(n,la[0]),0,-1): @@ -1610,7 +1615,7 @@ def PP_first_row_iter(n, la): if m < 0: yield return - if m==0: + if m == 0: yield [la] return for k in range(m,0,-1): @@ -1621,7 +1626,7 @@ def PP_first_row_iter(n, la): yield [la] + PP n = self._n - if n==0: + if n == 0: yield PlanePartition([]) return @@ -1732,15 +1737,15 @@ def to_poset(self): sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ - a=self._box[0] - c=self._box[2] + a = self._box[0] + c = self._box[2] pl = [] - cmp = lambda x,y : all(x[i]<=y[i] for i in range(len(x))) + def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) for x in range(0,a): for y in range(0,x+1): for z in range(0,c): pl.append((x,y,z)) - return Poset((pl,cmp)) + return Poset((pl,comp)) def from_order_ideal(self, I) -> PP: r""" @@ -1769,15 +1774,15 @@ def from_antichain(self, A) -> PP: Plane partition [[2, 2, 1], [2, 1, 1], [1, 1, 1]] """ #Initialize an empty plane partition - a=self._box[0] - b=self._box[1] + a = self._box[0] + b = self._box[1] ppMatrix = [[0] * (b) for i in range(a)] #Antichain indicates where the 'corners' will be in the #plane partition for ac in A: - x=ac[0] - y=ac[1] - z=ac[2] + x = ac[0] + y = ac[1] + z = ac[2] ppMatrix[x][y] = (z+1) #Fill out the rest of the plane partition using symmetry and the #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) @@ -1786,7 +1791,7 @@ def from_antichain(self, A) -> PP: i = a-(i+1) for j in range(b): j = b-(j+1) - if (ppMatrix[i][j] == 0) and i>=j: + if (ppMatrix[i][j] == 0) and i >= j: iValue = 0 jValue = 0 if i < a-1: @@ -1932,11 +1937,11 @@ def to_poset(self): sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ - a=self._box[0] - b=self._box[1] - c=self._box[2] - comp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) - comp2 = lambda x,y : comp(x,y) or comp(x,(y[2],y[0],y[1])) or comp(x,(y[1],y[2],y[0])) + a = self._box[0] + b = self._box[1] + c = self._box[2] + def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) + def comp2(x,y): return(comp(x,y) or comp(x,(y[2],y[0],y[1])) or comp(x,(y[1],y[2],y[0]))) pl = [] for x in range(0,a): for y in range(0, b): @@ -1957,8 +1962,8 @@ def from_antichain(self, acl) -> PP: sage: PP.from_antichain(A) Plane partition [[3, 3, 3], [3, 2, 1], [3, 1, 1]] """ - b=self._box[1] - c=self._box[2] + b = self._box[1] + c = self._box[2] ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane partition populated by 0s #EX: [[0,0,0], [0,0,0], [0,0,0]] @@ -2141,16 +2146,16 @@ def to_poset(self): sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ - a=self._box[0] - b=self._box[1] - c=self._box[2] - cmp = lambda x,y : all(x[i]<= y[i] for i in range(len(x))) + a = self._box[0] + b = self._box[1] + c = self._box[2] + def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) pl = [] for x in range(0,a): for y in range(x, b): for z in range(y,c): pl.append((x,y,z)) - return Poset((pl,cmp)) + return Poset((pl,comp)) def from_antichain(self, acl) -> PP: r""" @@ -2164,8 +2169,8 @@ def from_antichain(self, acl) -> PP: sage: PP.from_antichain(A) Plane partition [[3, 2, 1], [2, 1], [1]] """ - b=self._box[1] - c=self._box[2] + b = self._box[1] + c = self._box[2] ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane #partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] for ac in acl: @@ -2325,12 +2330,12 @@ def __iter__(self) -> Iterator: Plane partition [[2, 1], [2], [1]], Plane partition [[2, 2], [2]]] """ - b=self._box[0] - a=self._box[1] - c=self._box[2] + b = self._box[0] + a = self._box[1] + c = self._box[2] def Partitions_inside_lambda(la): "Returns the list of partitions contained in la with the same number of parts including 0s." - if len(la)==0: + if len(la) == 0: yield [] return for mu_0 in range(la[0],0,-1): @@ -2342,7 +2347,7 @@ def Partitions_inside_lambda(la): def Partitions_inside_lambda_with_smallest_at_least_k(la,k): "Returns the list of partitions contained in la with the smallest entry at least k" - if len(la)==0: + if len(la) == 0: yield [] return if la[-1] < k: @@ -2360,7 +2365,7 @@ def possible_middle_row_for_b_odd(a,c): return for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor(a/2))]): nu = [c-mu[len(mu)-1-i] for i in range(len(mu))] - if a % 2 ==0: + if a % 2 == 0: la = nu + mu else: la = nu + [c/2] + mu @@ -2453,9 +2458,9 @@ def cardinality(self) -> Integer: sage: P.cardinality() 2500 """ - r=self._box[0] - s=self._box[1] - t=self._box[2] + r = self._box[0] + s = self._box[1] + t = self._box[2] if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) if r % 2 == 1 and s % 2 == 0 and t % 2 == 0: @@ -2560,8 +2565,8 @@ def cardinality(self) -> Integer: 5 """ - a=self._box[0] - c=self._box[2] + 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,1+a-2) for i in range(1,1+j))) # Class 7 @@ -2597,7 +2602,7 @@ def __init__(self, box_size): ... ValueError: z dimension (3) must be even """ - if box_size[0]!=box_size[1]: + if box_size[0] != box_size[1]: raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) if (box_size[2] % 2 == 1): raise ValueError("z dimension ({}) must be even".format(box_size[2])) @@ -2663,8 +2668,8 @@ def cardinality(self) -> Integer: """ - a=self._box[0] - c=self._box[2] + 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+floor(a/2)) for j in range(1,1+ceil(a/2)) @@ -2752,7 +2757,7 @@ def cardinality(self) -> Integer: sage: P.cardinality() 11 """ - a=self._box[0] + a = self._box[0] return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range((a/2)))) # Class 9 @@ -2838,7 +2843,7 @@ def cardinality(self) -> Integer: sage: P.cardinality() 49 """ - a=self._box[0] + a = self._box[0] return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) # Class 10 @@ -2905,15 +2910,10 @@ def to_poset(self): sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ - cmp = lambda x,y : all(x[i] <= y[i] for i in range(len(x))) - def componentwise_comparer(thing1,thing2): - if len(thing1) == len(thing2): - if all(thing1[i] <= thing2[i] for i in range(len(thing1))): - return True - return False - a=self._box[0] - b=self._box[1] - c=self._box[2] + def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) + a = self._box[0] + b = self._box[1] + c = self._box[2] if a != b or b != c or a != c: return @@ -2924,7 +2924,7 @@ def componentwise_comparer(thing1,thing2): if z <= a/2 - 2 - y: pl.append((x,y,z)) - return Poset((pl,cmp)) + return Poset((pl,comp)) def from_antichain(self, acl) -> PP: r""" @@ -2939,10 +2939,10 @@ def from_antichain(self, acl) -> PP: Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 4, 3, 1], [6, 5, 4, 3, 2, 1], [5, 4, 3, 2, 1], [5, 3, 2, 1, 1], [3, 1, 1]] """ #ac format ex: [x,y,z] - a=self._box[0] - b=self._box[1] - c=self._box[2] - n=a + a = self._box[0] + b = self._box[1] + c = self._box[2] + n = a ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s #EX: [[0,0,0], [0,0,0], [0,0,0]] @@ -3064,5 +3064,5 @@ def cardinality(self) -> Integer: sage: P.cardinality() 7 """ - a=self._box[0] + a = self._box[0] return Integer(prod( ((factorial(3*i+1)/(factorial(a/2+i)) for i in range((a/2)))))) From 8d6bbd57fa8289e4cc5dc3d7ad15ae716557ebbf Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 14 Sep 2021 11:13:28 -0500 Subject: [PATCH 67/74] bug fix for failure at basic logic --- src/sage/combinat/plane_partition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index de0df50c671..c959c954cfe 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1435,7 +1435,7 @@ def from_antichain(self, A) -> PP: ppMatrix[x][y] = (z+1) #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format - if not A: + if A: for i in range(a): i = a-(i+1) for j in range(b): @@ -1786,7 +1786,7 @@ def from_antichain(self, A) -> PP: ppMatrix[x][y] = (z+1) #Fill out the rest of the plane partition using symmetry and the #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) - if not A: + if A: for i in range(a): i = a-(i+1) for j in range(b): From 73b86c7f46579f428a90803b3b1ed944b083fd9d Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 14 Sep 2021 13:29:08 -0500 Subject: [PATCH 68/74] moved classcall to factory class --- src/sage/combinat/plane_partition.py | 308 +++++++++++++-------------- 1 file changed, 153 insertions(+), 155 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index c959c954cfe..9a7967bb17d 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -683,11 +683,10 @@ def contains(self, PP) -> bool: if len(self) < len(PP): return False - for i in range(len(PP)): - if len(self[i]) < len(PP[i]): - return False - - return all([self[i][j] >= PP[i][j] for j in range(len(PP[i])) for i in range(len(PP))]) + if any(len(self[i]) < len(PP[i]) for i in range(len(PP))): + return False + + return all(self[i][j] >= val for i,row in enumerate(PP) for j, val in enumerate(row)) def complement(self, tableau_only=False) -> PP: r""" @@ -1074,46 +1073,46 @@ class PlanePartitions(UniqueRepresentation, Parent): plane partitions inside a box of the specified size satisfying certain symmetry conditions. - - ``symmetry = 'SPP'`` gives the class of symmetric plane partitions. which - is all plane partitions fixed under reflection across the diagonal. - Requires that `a = b`. + - ``symmetry = 'SPP'`` gives the class of symmetric plane partitions. which + is all plane partitions fixed under reflection across the diagonal. + Requires that `a = b`. - - ``symmetry = 'CSPP'`` gives the class of cyclic plane partitions, which - is all plane partitions fixed under cyclic rotation of coordinates. - Requires that `a = b = c`. + - ``symmetry = 'CSPP'`` gives the class of cyclic plane partitions, which + is all plane partitions fixed under cyclic rotation of coordinates. + Requires that `a = b = c`. - - ``symmetry = 'TSPP'`` gives the class of totally symmetric plane partitions, - which is all plane partitions fixed under any interchanging of coordinates. - Requires that `a = b = c`. + - ``symmetry = 'TSPP'`` gives the class of totally symmetric plane partitions, + which is all plane partitions fixed under any interchanging of coordinates. + Requires that `a = b = c`. - - ``symmetry = 'SCPP'`` gives the class of self-complementary plane partitions. - which is all plane partitions that are equal to their own complement - in the specified box. Requires at least one of `a,b,c` be even. + - ``symmetry = 'SCPP'`` gives the class of self-complementary plane partitions. + which is all plane partitions that are equal to their own complement + in the specified box. Requires at least one of `a,b,c` be even. - - ``symmetry = 'TCPP'`` gives the class of transpose complement plane partitions, - which is all plane partitions whose complement in the box of the specified - size is equal to their transpose. Requires `a = b` and at least one of - `a,b,c` be even. - - - ``symmetry = 'SSCPP'`` gives the class of symmetric self-complementary - plane partitions, which is all plane partitions that are both - symmetric and self-complementary. Requires `a = b` and at least one of - `a,b,c` be even. - - - ``symmetry = 'CSTCPP'`` gives the class of cyclically symmetric transpose - complement plane partitions, which is all plane partitions that are - both symmetric and equal to the transpose of their complement. Requires - `a = b = c`. - - - ``symmetry = 'CSSCPP'`` gives the class of cyclically symmetric - self-complementary plane partitions, which is all plane partitions that - are both cyclically symmetric and self-complementary. Requires `a = b = c` - and at least one of `a,b,c` be even. - - - ``symmetry = 'TSSCPP'`` gives the class of totally symmetric - self-complementary plane partitions, which is all plane partitions that - are totally symmetric and also self-complementary. Requires `a = b = c` - and at least one of `a,b,c` be even. + - ``symmetry = 'TCPP'`` gives the class of transpose complement plane partitions, + which is all plane partitions whose complement in the box of the specified + size is equal to their transpose. Requires `a = b` and at least one of + `a,b,c` be even. + + - ``symmetry = 'SSCPP'`` gives the class of symmetric self-complementary + plane partitions, which is all plane partitions that are both + symmetric and self-complementary. Requires `a = b` and at least one of + `a,b,c` be even. + + - ``symmetry = 'CSTCPP'`` gives the class of cyclically symmetric transpose + complement plane partitions, which is all plane partitions that are + both symmetric and equal to the transpose of their complement. Requires + `a = b = c`. + + - ``symmetry = 'CSSCPP'`` gives the class of cyclically symmetric + self-complementary plane partitions, which is all plane partitions that + are both cyclically symmetric and self-complementary. Requires `a = b = c` + and at least one of `a,b,c` be even. + + - ``symmetry = 'TSSCPP'`` gives the class of totally symmetric + self-complementary plane partitions, which is all plane partitions that + are totally symmetric and also self-complementary. Requires `a = b = c` + and at least one of `a,b,c` be even. EXAMPLES: @@ -1198,7 +1197,7 @@ def __classcall_private__(cls, *args, **kwds): if isinstance(args[0], (int, Integer)): return PlanePartitions_n(args[0]) else: - box_size = args[0] + box_size = tuple(args[0]) if symmetry is None: return PlanePartitions_box(box_size) elif symmetry == 'SPP': @@ -1324,19 +1323,19 @@ class PlanePartitions_box(PlanePartitions): will have at most 'a' rows, of lengths at most 'b', with entries at most 'c'. """ - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) - sage: P1 is P2 - True - """ - return super(PlanePartitions_box, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((4,3,2)) +# sage: P2 = PlanePartitions([4,3,2]) +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_box, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): r""" @@ -1668,19 +1667,19 @@ def cardinality(self) -> Integer: # Symmetric Plane Partitions class PlanePartitions_SPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((3,3,2), symmetry='SPP') - sage: P2 = PlanePartitions([3,3,2], symmetry='SPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_SPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((3,3,2), symmetry='SPP') +# sage: P2 = PlanePartitions([3,3,2], symmetry='SPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_SPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -1868,19 +1867,19 @@ def random_element(self) -> PP: # Cyclically Symmetric Plane Partitions class PlanePartitions_CSPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((4,4,4), symmetry='CSPP') - sage: P2 = PlanePartitions([4,4,4], symmetry='CSPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((4,4,4), symmetry='CSPP') +# sage: P2 = PlanePartitions([4,4,4], symmetry='CSPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_CSPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -2077,19 +2076,19 @@ def cardinality(self) -> Integer: # Totally Symmetric Plane Partitions class PlanePartitions_TSPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((4,4,4), symmetry='TSPP') - sage: P2 = PlanePartitions([4,4,4], symmetry='TSPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((4,4,4), symmetry='TSPP') +# sage: P2 = PlanePartitions([4,4,4], symmetry='TSPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -2257,19 +2256,19 @@ def cardinality(self) -> Integer: # Self-complementary Plane Partitions class PlanePartitions_SCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2), symmetry='SCPP') - sage: P2 = PlanePartitions([4,3,2], symmetry='SCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((4,3,2), symmetry='SCPP') +# sage: P2 = PlanePartitions([4,3,2], symmetry='SCPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -2482,19 +2481,19 @@ def cardinality(self) -> Integer: # Transpose-complement Plane Partitions class PlanePartitions_TCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((3,3,2), symmetry='TCPP') - sage: P2 = PlanePartitions([3,3,2], symmetry='TCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_TCPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((3,3,2), symmetry='TCPP') +# sage: P2 = PlanePartitions([3,3,2], symmetry='TCPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_TCPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -2573,19 +2572,19 @@ def cardinality(self) -> Integer: # Symmetric Self-complementary Plane Partitions class PlanePartitions_SSCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((4,4,2), symmetry='SSCPP') - sage: P2 = PlanePartitions([4,4,2], symmetry='SSCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_SSCPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((4,4,2), symmetry='SSCPP') +# sage: P2 = PlanePartitions([4,4,2], symmetry='SSCPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_SSCPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -2679,19 +2678,19 @@ def cardinality(self) -> Integer: #Cyclically Symmetric Transpose-complement Partitions class PlanePartitions_CSTCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((2,2,2), symmetry='CSTCPP') - sage: P2 = PlanePartitions([2,2,2], symmetry='CSTCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((2,2,2), symmetry='CSTCPP') +# sage: P2 = PlanePartitions([2,2,2], symmetry='CSTCPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -2764,20 +2763,19 @@ def cardinality(self) -> Integer: # Cyclically Symmetric Self-complementary Plane Partitions class PlanePartitions_CSSCPP(PlanePartitions): +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: +# EXAMPLES:: - sage: P1 = PlanePartitions((4,4,4), symmetry='CSSCPP') - sage: P2 = PlanePartitions([4,4,4], symmetry='CSSCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) +# sage: P1 = PlanePartitions((4,4,4), symmetry='CSSCPP') +# sage: P2 = PlanePartitions([4,4,4], symmetry='CSSCPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ @@ -2850,19 +2848,19 @@ def cardinality(self) -> Integer: # Totally Symmetric Self-complementary Plane Partitions class PlanePartitions_TSSCPP(PlanePartitions): - @staticmethod - def __classcall_private__(cls, box_size): - """ - Normalize input to ensure a unique representation. - - EXAMPLES:: - - sage: P1 = PlanePartitions((4,4,4), symmetry='TSSCPP') - sage: P2 = PlanePartitions([4,4,4], symmetry='TSSCPP') - sage: P1 is P2 - True - """ - return super(PlanePartitions_TSSCPP, cls).__classcall__(cls, tuple(box_size)) +# @staticmethod +# def __classcall_private__(cls, box_size): +# """ +# Normalize input to ensure a unique representation. + +# EXAMPLES:: + +# sage: P1 = PlanePartitions((4,4,4), symmetry='TSSCPP') +# sage: P2 = PlanePartitions([4,4,4], symmetry='TSSCPP') +# sage: P1 is P2 +# True +# """ +# return super(PlanePartitions_TSSCPP, cls).__classcall__(cls, tuple(box_size)) def __init__(self, box_size): """ From ce29cc88db2d5265a7dc4b2d1673ba1a25c267b7 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Tue, 14 Sep 2021 14:41:43 -0500 Subject: [PATCH 69/74] faster maximal boxes method --- src/sage/combinat/plane_partition.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 9a7967bb17d..82252597a01 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -987,17 +987,12 @@ def maximal_boxes(self) -> list: sage: sorted(PlanePartition([[2,1],[1],[1]]).maximal_boxes()) [[0, 0, 1], [0, 1, 0], [2, 0, 0]] """ - (a, b, c) = (self._max_x, self._max_y, self._max_z) - Q = posets.ProductOfChains([a,b,c]) - count = 0 generate = [] - for i in range(len(self)): - for j in range(len(self[i])): - if (self[i][j] > 0): - generate.append((i,j,self[i][j]-1)) - count += 1 - oi = Q.order_ideal_generators(generate) - return [list(oi_elem) for oi_elem in oi] + for i,row in enumerate(self): + 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) def cyclically_rotate(self, preserve_parent=False) -> PP: r""" @@ -1039,11 +1034,11 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: z = box[1] x = box[2] ppMatrix[y][z] = (x+1) - if new_antichain != []: + if new_antichain: for i in range(b): - i = b-(i+1) + i = b - (i+1) for j in range(c): - j = c-(j+1) + j = c - (j+1) if (ppMatrix[i][j] == 0): iValue = 0 jValue = 0 From 40842e8e14080fff7422d902071de93051dc4820 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Thu, 4 Nov 2021 00:48:58 -0500 Subject: [PATCH 70/74] removed unused imports --- src/sage/combinat/plane_partition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index d07548ac94d..a72b3725155 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -27,7 +27,7 @@ from __future__ import annotations #from typing import Iterator -from typing import NewType, Iterator, Tuple +from typing import NewType, Iterator from sage.structure.list_clone import ClonableArray from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.richcmp import richcmp, richcmp_method @@ -47,7 +47,7 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.categories.sets_cat import Sets +#from sage.categories.sets_cat import Sets PP = NewType('PP', 'PlanePartition') From 77a5b52bf50f0953dea2f1c57f7de6c61d7f50da Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 27 Jan 2023 11:49:09 +0900 Subject: [PATCH 71/74] A number of reviewer changes and cleanup. --- src/sage/combinat/plane_partition.py | 851 +++++++++++++-------------- 1 file changed, 412 insertions(+), 439 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index fc82cdbe886..638b43624e7 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -26,30 +26,18 @@ # **************************************************************************** from __future__ import annotations -from typing import Iterator -#from typing import NewType, Iterator +from typing import NewType, Iterator -from sage.structure.list_clone import ClonableArray -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.richcmp import richcmp, richcmp_method -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.combinat.posets.posets import Poset -from sage.combinat.posets.poset_examples import posets -from sage.rings.integer import Integer -from sage.misc.misc_c import prod -#from sage.misc.all import prod from sage.combinat.tableau import Tableau from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module_element import vector from sage.rings.integer import Integer from sage.structure.list_clone import ClonableArray from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -lazy_import("sage.plot.plot3d.platonic", "cube") from sage.rings.all import ZZ from sage.arith.misc import Sigma from sage.functions.other import floor, ceil, binomial, factorial @@ -93,7 +81,7 @@ class PlanePartition(ClonableArray, sage: TestSuite(PP).run() """ @staticmethod - def __classcall_private__(cls, PP): + def __classcall_private__(cls, PP, box_size=None): """ Construct a plane partition with the appropriate parent. @@ -109,9 +97,9 @@ def __classcall_private__(cls, PP): sage: type(p) """ - if isinstance(PP,PlanePartition): + if isinstance(PP, PlanePartition) and box_size is None: return PP - pp = PlanePartitions() + pp = PlanePartitions(box_size=box_size) return pp.element_class(pp, PP) # The check() will raise the appropriate error def __init__(self, parent, pp, check=True): @@ -583,7 +571,9 @@ def _repr_svg_(self) -> str: vx = -vector([0.866, -0.5]) vy = -vector([-0.866, -0.5]) vz = -vector([0, 1]) - Nx, Ny, Nz = self.parent().box() + # Since we currently don't display the bounding box, just + # use the smallest one possible. + Nx, Ny, Nz = self.bounding_box() resu += '\"%.3f %.3f %.3f %.3f \">' % (-0.866 * Nx, -Nz, 0.866 * Nx + 0.866 * Ny, @@ -736,12 +726,11 @@ def add_rightside(i, j, k): TP.axes(show=False) return TP - def contains(self, PP) -> bool: + def contains(self, PP) -> bool: """ - Return ``True`` if ``PP`` is a plane partition that fits inside ``self``. - + Specifically, ``self`` contains ``PP`` if, for all `i`, `j`, the height of ``PP`` at `ij` is less than or equal to the height of ``self`` at `ij`. @@ -766,7 +755,7 @@ def contains(self, PP) -> bool: for i in range(len(PP)): if len(self[i]) < len(PP[i]): return False - return all([self[i][j] >= PP[i][j] for j in range(len(PP[i])) for i in range(len(PP))]) + return all(self[i][j] >= PP[i][j] for i,row in enumerate(PP) for j in range(len(row))) def plot3d(self, colors=None): r""" @@ -785,6 +774,7 @@ def plot3d(self, colors=None): """ if colors is None: colors = ["white", "lightgray", "darkgray"] + from sage.plot.plot3d.platonic import cube return sum(cube(c, color=colors, frame_thickness=2, frame_color='black', frame=False) for c in self.cells()) @@ -824,7 +814,7 @@ def complement(self, tableau_only=False) -> PP: elif not self.parent()._box: pp = PlanePartitions() return pp.element_class(pp, T) - else: + else: return type(self)(self.parent(), T, check=False) def transpose(self, tableau_only=False) -> PP: @@ -1062,6 +1052,7 @@ def to_order_ideal(self): sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] """ + from sage.combinat.posets.poset_examples import posets (a, b, c) = (self._max_x, self._max_y, self._max_z) Q = posets.ProductOfChains([a,b,c]) count = 0 @@ -1075,10 +1066,10 @@ def to_order_ideal(self): return oi def maximal_boxes(self) -> list: - """ + r""" Return the coordinates of the maximal boxes of ``self``. - The maximal boxes of a plane partitions are the boxes that can be + The maximal boxes of a plane partitions are the boxes that can be removed from a plane partition and still yield a valid plane partition. EXAMPLES:: @@ -1134,7 +1125,7 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: y = box[0] z = box[1] x = box[2] - ppMatrix[y][z] = (x+1) + ppMatrix[y][z] = x + 1 if new_antichain: for i in range(b): i = b - (i+1) @@ -1149,28 +1140,43 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: jValue = ppMatrix[i][j+1] ppMatrix[i][j] = max(iValue,jValue) # Start code for determining correct parent - if self.parent()._box is None or preserve_parent or (self.parent()._box[0] == self.parent()._box[1] == self.parent()._box[2]): - return type(self)(self.parent(), ppMatrix, check=False) - new_box = (self.parent()._box[2],self.parent()._box[0],self.parent()._box[1]) - return PlanePartitions(new_box,symmetry=self.parent()._symmetry)(ppMatrix) + P = self.parent() + if P._box is None or preserve_parent or (P._box[0] == P._box[1] == P._box[2]): + return type(self)(P, ppMatrix, check=False) + new_box = (P._box[2], P._box[0], P._box[1]) + return PlanePartitions(new_box,symmetry=P._symmetry)(ppMatrix) -PP = PlanePartition + def bounding_box(self): + r""" + Return the smallest box `(a, b, c)` that ``self`` is contained in. + + EXAMPLES:: + + sage: PP = PlanePartition([[5,2,1,1], [2,2], [2]]) + sage: PP.bounding_box() + (3, 4, 5) + """ + if not self: + return (0, 0, 0) + return (len(self), len(self[0]), self[0][0]) +#PP = PlanePartition class PlanePartitions(UniqueRepresentation, Parent): r""" - A factory class for plane partitions. + Plane partitions. - PlanePartitions() returns the class of all plane partitions. + ``PlanePartitions()`` returns the class of all plane partitions. - PlanePartitions(n) return the class of all plane partitions with `n` boxes. + ``PlanePartitions(n)`` return the class of all plane partitions with + precisely `n` boxes. - PlanePartitions([a,b,c]) returns the class of plane partitions that fit + ``PlanePartitions([a,b,c]) returns the class of plane partitions that fit inside an `a \times b \times c` box. - PlanePartitions([a,b,c]) has optional keyword is 'symmetry', which gives all - plane partitions inside a box of the specified size satisfying certain - symmetry conditions. + ``PlanePartitions([a,b,c])`` has the optional keyword ``symmetry``, which + restricts the plane partitions inside a box of the specified size satisfying + certain symmetry conditions. - ``symmetry = 'SPP'`` gives the class of symmetric plane partitions. which is all plane partitions fixed under reflection across the diagonal. @@ -1215,14 +1221,16 @@ class PlanePartitions(UniqueRepresentation, Parent): EXAMPLES: - If no arguments are passed, then the class of all plane partitions is returned:: + If no arguments are passed, then the class of all plane partitions + is returned:: sage: PlanePartitions() Plane partitions sage: [[2,1],[1]] in PlanePartitions() True - If an integer `n` is passed, then the class of plane partitions of `n` is returned:: + If an integer `n` is passed, then the class of plane partitions of `n` + is returned:: sage: PlanePartitions(3) Plane partitions of size 3 @@ -1244,7 +1252,7 @@ class PlanePartitions(UniqueRepresentation, Parent): If an additional keyword ``symmetry`` is pass along with a three-element tuple or list `[a,b,c]`, then the class of all plane partitions that fit - inside an `a\times b\times c` box with the specified symmetry is returned:: + inside an `a \times b \times c` box with the specified symmetry is returned:: sage: PlanePartitions([2,2,2], symmetry='CSPP') Cyclically symmetric plane partitions inside a 2 x 2 x 2 box @@ -1271,9 +1279,9 @@ class PlanePartitions(UniqueRepresentation, Parent): @staticmethod def __classcall_private__(cls, *args, **kwds): r""" - This is a factory class which returns the appropriate parent based on - arguments. See the documentation for :class:`PlanePartitions` - for more information. + Return the appropriate parent based on arguments. + + See the documentation for :class:`PlanePartitions` for more information. TESTS:: @@ -1287,38 +1295,56 @@ def __classcall_private__(cls, *args, **kwds): Totally symmetric self-complementary plane partitions inside a 4 x 4 x 4 box """ symmetry = kwds.get('symmetry', None) - if not args: + box_size = kwds.get('box_size', None) + + if not args and symmetry is None and box_size is None: return PlanePartitions_all() - else: - box_size = None - if args: - # The first arg could be either a size or a box size - if isinstance(args[0], (int, Integer)): - return PlanePartitions_n(args[0]) - else: - box_size = tuple(args[0]) - if symmetry is None: - return PlanePartitions_box(box_size) - elif symmetry == 'SPP': - return PlanePartitions_SPP(box_size) - elif symmetry == 'CSPP': - return PlanePartitions_CSPP(box_size) - elif symmetry == 'TSPP': - return PlanePartitions_TSPP(box_size) - elif symmetry == 'SCPP': - return PlanePartitions_SCPP(box_size) - elif symmetry == 'TCPP': - return PlanePartitions_TCPP(box_size) - elif symmetry == 'SSCPP': - return PlanePartitions_SSCPP(box_size) - elif symmetry == 'CSTCPP': - return PlanePartitions_CSTCPP(box_size) - elif symmetry == 'CSSCPP': - return PlanePartitions_CSSCPP(box_size) - elif symmetry == 'TSSCPP': - return PlanePartitions_TSSCPP(box_size) - else: - raise ValueError("invalid symmetry class option; must be None, 'SPP', 'CSPP', 'TSPP', 'SCPP', 'TCPP', 'SSCPP', 'CSTCPP', 'CSSCPP', or 'TSSCPP' ") + + 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]) + + box_size = args[0] + + box_size = tuple(box_size) + if symmetry is None: + return PlanePartitions_box(box_size) + elif symmetry == 'SPP': + return PlanePartitions_SPP(box_size) + elif symmetry == 'CSPP': + return PlanePartitions_CSPP(box_size) + elif symmetry == 'TSPP': + return PlanePartitions_TSPP(box_size) + elif symmetry == 'SCPP': + return PlanePartitions_SCPP(box_size) + elif symmetry == 'TCPP': + return PlanePartitions_TCPP(box_size) + elif symmetry == 'SSCPP': + return PlanePartitions_SSCPP(box_size) + elif symmetry == 'CSTCPP': + return PlanePartitions_CSTCPP(box_size) + elif symmetry == 'CSSCPP': + return PlanePartitions_CSSCPP(box_size) + elif symmetry == 'TSSCPP': + return PlanePartitions_TSSCPP(box_size) + + raise ValueError("invalid symmetry class option") + + def __init__(self, box_size=None, symmetry=None, category=None): + r""" + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions(box_size=[2,2,1]) + sage: TestSuite(PP).run() + """ + if box_size is not None and len(box_size) != 3: + raise ValueError("invalid box size") + self._box = box_size + self._symmetry = symmetry + Parent.__init__(self, category=category) Element = PlanePartition @@ -1334,7 +1360,6 @@ def __contains__(self, pp): False sage: [[3,2,1],[3,3]] in PlanePartitions() False - """ if isinstance(pp, PlanePartition): return True @@ -1348,22 +1373,48 @@ def __contains__(self, pp): return False if not all(row[i] >= row[i+1] for i in range(len(row)-1)): return False - for row, next in zip(pp, pp[1:]): - if not all(row[c] >= next[c] for c in range(len(next))): + for row, nxt in zip(pp, pp[1:]): + if not all(row[c] >= nxt[c] for c in range(len(nxt))): return False return True return False + def box(self) -> tuple: + """ + Return the size of the box of the plane partition of ``self`` + is contained in. + + EXAMPLES:: + + sage: P = PlanePartitions([4,3,5]) + sage: P.box() + (4, 3, 5) + + sage: PP = PlanePartitions() + sage: PP.box() is None + True + """ + return self._box + + def symmetry(self) -> str: + """ + Return the symmetry class of ``self``. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: PP.symmetry() + 'SPP' + sage: PP = PlanePartitions() + sage: PP.symmetry() is None + True + """ + return self._symmetry + class PlanePartitions_all(PlanePartitions, DisjointUnionEnumeratedSets): r""" All plane partitions. - - .. TODO:: - - Consider giving this the structure of disjoint union of the classes - PlanePartitions(n) for n an integer. """ - def __init__(self): r""" Initializes the class of all plane partitions. @@ -1379,16 +1430,14 @@ def __init__(self): sage: P = PlanePartitions_all() sage: TestSuite(P).run() # long time """ + # We manually set these here rather than invoking the super().__init__(). + # This is so DisjointUnionEnumeratedSets can make the Parent.__init__() call. self._box = None self._symmetry = None #super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) - #super(PlanePartitions_all, self).__init__(category=Sets()) - #super(PlanePartitions_all, self).__init__(category=DisjointUnionEnumeratedSets()) - def PP_n(n): - return PlanePartitions_n(n) DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), PP_n), + Family(NonNegativeIntegers(), PlanePartitions_n), facade=True, keepkey=False) def _repr_(self) -> str: @@ -1446,12 +1495,9 @@ def __init__(self, box_size): sage: PP = PlanePartitions([4,3,2]) sage: TestSuite(PP).run() """ - super(PlanePartitions_box,self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = None + super().__init__(box_size, category=FiniteEnumeratedSets()) def _repr_(self) -> str: - """ Return a string representation of ``self``. @@ -1460,7 +1506,6 @@ def _repr_(self) -> str: sage: PlanePartitions([4,3,2]) Plane partitions inside a 4 x 3 x 2 box """ - return "Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) @@ -1494,6 +1539,7 @@ def to_poset(self): a = self._box[0] b = self._box[1] c = self._box[2] + from sage.combinat.posets.poset_examples import posets return posets.ProductOfChains([a,b,c]) def from_order_ideal(self, I) -> PP: @@ -1551,14 +1597,13 @@ def from_antichain(self, A) -> PP: def __iter__(self) -> Iterator: r""" - An iterator for all partitions that fit inside a box. + Iterate over all partitions that fit inside a box. EXAMPLES:: sage: list(PlanePartitions([1,2,1])) [Plane partition [], Plane partition [[1]], Plane partition [[1, 1]]] """ - A = self._box[0] B = self._box[1] C = self._box[2] @@ -1596,19 +1641,6 @@ def cardinality(self) -> Integer: for j in range(1, B + 1) for k in range(1, C + 1))) - def box(self) -> tuple: - """ - Return the size of the box of the plane partition of ``self`` - is contained in. - - EXAMPLES:: - - sage: P = PlanePartitions([4,3,5]) - sage: P.box() - (4, 3, 5) - """ - return self._box - def random_element(self) -> PP: r""" Return a uniformly random plane partition inside a box. @@ -1632,7 +1664,6 @@ class PlanePartitions_n(PlanePartitions): """ Plane partitions with a fixed number of boxes. """ - def __init__(self, n): r""" Initializes the class of plane partitions with ``n`` boxes. @@ -1651,8 +1682,6 @@ def __init__(self, n): """ super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) self._n = n - self._box = None - self._symmetry = None def _repr_(self) -> str: """ @@ -1676,7 +1705,7 @@ def __contains__(self, x) -> bool: def __iter__(self) -> Iterator: r""" - An iterator to generate all plane partitions of a fixed size. + Iterate over all plane partitions of a fixed size. EXAMPLES:: @@ -1764,22 +1793,11 @@ def cardinality(self) -> Integer: # Class 2 # Symmetric Plane Partitions - class PlanePartitions_SPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((3,3,2), symmetry='SPP') -# sage: P2 = PlanePartitions([3,3,2], symmetry='SPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_SPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + symmetric. + """ def __init__(self, box_size): """ TESTS:: @@ -1793,9 +1811,7 @@ def __init__(self, box_size): """ if box_size[0] != box_size[1]: raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) - super(PlanePartitions_SPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'SPP' + super().__init__(box_size, "SPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -1837,12 +1853,12 @@ def to_poset(self): """ a = self._box[0] c = self._box[2] - pl = [] - def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) - for x in range(0,a): - for y in range(0,x+1): - for z in range(0,c): - pl.append((x,y,z)) + + def comp(x,y): + return all(a <= b for a,b in zip(x, y)) + + pl = [(x,y,z) for x in range(a) for y in range(x+1) for z in range(c)] + from sage.combinat.posets.posets import Poset return Poset((pl,comp)) def from_order_ideal(self, I) -> PP: @@ -1873,7 +1889,7 @@ def from_antichain(self, A) -> PP: """ #Initialize an empty plane partition a = self._box[0] - b = self._box[1] + b = self._box[1] ppMatrix = [[0] * (b) for i in range(a)] #Antichain indicates where the 'corners' will be in the #plane partition @@ -1881,7 +1897,7 @@ def from_antichain(self, A) -> PP: x = ac[0] y = ac[1] z = ac[2] - ppMatrix[x][y] = (z+1) + ppMatrix[x][y] = z + 1 #Fill out the rest of the plane partition using symmetry and the #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) if A: @@ -1889,21 +1905,21 @@ def from_antichain(self, A) -> PP: i = a-(i+1) for j in range(b): j = b-(j+1) - if (ppMatrix[i][j] == 0) and i >= j: + if ppMatrix[i][j] == 0 and i >= j: iValue = 0 jValue = 0 - if i < a-1: + if i < a - 1: iValue = ppMatrix[i+1][j] - if j < b-1: + if j < b - 1: jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) + ppMatrix[i][j] = max(iValue, jValue) elif j>i: ppMatrix[i][j] = ppMatrix[j][i] return self.element_class(self, ppMatrix) def __iter__(self) -> Iterator: """ - An iterator for symmetric plane partitions. + Iterate over all symmetric plane partitions. EXAMPLES:: @@ -1962,24 +1978,14 @@ def random_element(self) -> PP: Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) + # Class 3 # Cyclically Symmetric Plane Partitions - class PlanePartitions_CSPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((4,4,4), symmetry='CSPP') -# sage: P2 = PlanePartitions([4,4,4], symmetry='CSPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_CSPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + cyclically symmetric. + """ def __init__(self, box_size): """ TESTS:: @@ -1993,9 +1999,7 @@ def __init__(self, box_size): """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) - super(PlanePartitions_CSPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'CSPP' + super().__init__(box_size, "CSPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -2038,14 +2042,16 @@ def to_poset(self): a = self._box[0] b = self._box[1] c = self._box[2] - def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) - def comp2(x,y): return(comp(x,y) or comp(x,(y[2],y[0],y[1])) or comp(x,(y[1],y[2],y[0]))) - pl = [] - for x in range(0,a): - for y in range(0, b): - for z in range(x,c): - if y <= z and (x != z or y == x): - pl.append((x,y,z)) + + def comp(x, y): + return all(a <= b for a, b in zip(x, y)) + + def comp2(x, y): + return(comp(x, y) or comp(x, (y[2],y[0],y[1])) or comp(x, (y[1],y[2],y[0]))) + + pl = [(x,y,z) for x in range(a) for y in range(b) for z in range(x,c) + if y <= z and (x != z or y == x)] + from sage.combinat.posets.posets import Poset return Poset((pl, comp2)) def from_antichain(self, acl) -> PP: @@ -2079,17 +2085,17 @@ def from_antichain(self, acl) -> PP: #now in plane partition format if acl != []: for i in range(b): - i = b-(i+1) + i = b - (i + 1) for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): + j = c - (j + 1) + if ppMatrix[i][j] == 0: iValue = 0 jValue = 0 - if i < b-1: + if i < b - 1: iValue = ppMatrix[i+1][j] - if j < c-1: + if j < c - 1: jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) + ppMatrix[i][j] = max(iValue, jValue) return self.element_class(self, ppMatrix) def from_order_ideal(self, I) -> PP: @@ -2128,7 +2134,7 @@ def random_element(self) -> PP: def __iter__(self) -> Iterator: """ - An iterator for cyclically symmetric plane partitions. + Iterate over all cyclically symmetric plane partitions. EXAMPLES:: @@ -2173,22 +2179,11 @@ def cardinality(self) -> Integer: # Class 4 # Totally Symmetric Plane Partitions - class PlanePartitions_TSPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((4,4,4), symmetry='TSPP') -# sage: P2 = PlanePartitions([4,4,4], symmetry='TSPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_TSPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + totally symmetric. + """ def __init__(self, box_size): """ TESTS:: @@ -2202,9 +2197,7 @@ def __init__(self, box_size): """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0], box_size[1], box_size[2])) - super(PlanePartitions_TSPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'TSPP' + super().__init__(box_size, "TSPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -2228,8 +2221,9 @@ def __contains__(self, x) -> bool: False """ P = PlanePartition(x) - max = (P._max_x, P._max_y, P._max_z) - return PlanePartitions.__contains__(self, x) and P.is_TSPP() and all( a<=b for a,b in zip(max,self._box)) + maxval = (P._max_x, P._max_y, P._max_z) + return (PlanePartitions.__contains__(self, x) and P.is_TSPP() + and all(a <= b for a,b in zip(maxval, self._box))) def to_poset(self): r""" @@ -2247,12 +2241,12 @@ def to_poset(self): a = self._box[0] b = self._box[1] c = self._box[2] - def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) - pl = [] - for x in range(0,a): - for y in range(x, b): - for z in range(y,c): - pl.append((x,y,z)) + + def comp(x,y): + return all(a <= b for a, b in zip(x, y)) + + pl = [(x,y,z) for x in range(a) for y in range(x, b) for z in range(y, c)] + from sage.combinat.posets.posets import Poset return Poset((pl,comp)) def from_antichain(self, acl) -> PP: @@ -2276,29 +2270,29 @@ def from_antichain(self, acl) -> PP: y = ac[1] z = ac[2] - ppMatrix[y][z] = (x+1) #x,y,z - ppMatrix[z][x] = (y+1) #y,z,x - ppMatrix[x][y] = (z+1) #z,x,y + ppMatrix[y][z] = x + 1 #x,y,z + ppMatrix[z][x] = y + 1 #y,z,x + ppMatrix[x][y] = z + 1 #z,x,y - ppMatrix[z][y] = (x+1) #x,z,y - ppMatrix[x][z] = (y+1) #y,x,z - ppMatrix[y][x] = (z+1) #z,y,x + ppMatrix[z][y] = x + 1 #x,z,y + ppMatrix[x][z] = y + 1 #y,x,z + ppMatrix[y][x] = z + 1 #z,y,x #for each value in current antichain, fill in the rest of the matrix by #rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format if acl != []: for i in range(b): - i = b-(i+1) + i = b - (i + 1) for j in range(c): - j = c-(j+1) - if (ppMatrix[i][j] == 0): + j = c - (j + 1) + if ppMatrix[i][j] == 0: iValue = 0 jValue = 0 - if i < b-1: + if i < b - 1: iValue = ppMatrix[i+1][j] - if j < c-1: + if j < c - 1: jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) + ppMatrix[i][j] = max(iValue, jValue) return self.element_class(self, ppMatrix) def from_order_ideal(self, I) -> PP: @@ -2353,22 +2347,11 @@ def cardinality(self) -> Integer: # Class 5 # Self-complementary Plane Partitions - class PlanePartitions_SCPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((4,3,2), symmetry='SCPP') -# sage: P2 = PlanePartitions([4,3,2], symmetry='SCPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_SCPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + self-complementary. + """ def __init__(self, box_size): """ TESTS:: @@ -2382,9 +2365,7 @@ def __init__(self, box_size): """ if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): raise ValueError("dimensions ({},{},{}) cannot all be odd".format(box_size[0],box_size[1],box_size[2])) - super(PlanePartitions_SCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'SCPP' + super().__init__(box_size, "SCPP", category=FiniteEnumeratedSets()) def __contains__(self, x) -> bool: """ @@ -2431,34 +2412,35 @@ def __iter__(self) -> Iterator: b = self._box[0] a = self._box[1] c = self._box[2] + def Partitions_inside_lambda(la): - "Returns the list of partitions contained in la with the same number of parts including 0s." - if len(la) == 0: + "Return the list of 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 for i in la] + yield [mu_0] + mu + yield [0] * len(la) return def Partitions_inside_lambda_with_smallest_at_least_k(la,k): - "Returns the list of partitions contained in la with the smallest entry at least k" - if len(la) == 0: + "Return the list of 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([la[i]-k for i in range(len(la))]): - yield ([mu[i]+k for i in range(len(la))]) + 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): - "Returns the list of possible middle row for SCPP inside box(a,b,c) when b is odd" - if a*c % 2 == 1: + "Return the list of possible middle row for SCPP inside box(a,b,c) when b is odd" + if a * c % 2 == 1: yield return for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor(a/2))]): @@ -2467,20 +2449,20 @@ def possible_middle_row_for_b_odd(a,c): la = nu + mu else: la = nu + [c/2] + mu - yield (la) + yield la return def possible_middle_row_for_b_even(a,c): - "Returns the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" + "Return the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor((a+1)/2))]): - nu = [c-mu[len(mu)-1-i] for i in range(floor(a/2))] + nu = [c - mu[len(mu)-1-i] for i in range(floor(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): - "Returns PPs with first row la and with k rows in total" + "Return PPs with first row la and with k rows in total" if k == 0: yield [] return @@ -2488,12 +2470,12 @@ def PPs_with_first_row_la_and_with_k_rows(la,k): yield [la] return for mu in Partitions_inside_lambda(la): - for PP in PPs_with_first_row_la_and_with_k_rows(mu,k-1): + for PP in PPs_with_first_row_la_and_with_k_rows(mu, k-1): yield ([la]+PP) return def complement(PP,c): - "Returns the complement of PP with respect to height c" + "Return the complement of PP with respect to height c" if len(PP) == 0: return [] b = len(PP) @@ -2501,17 +2483,17 @@ 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 - for PP in PPs_with_first_row_la_and_with_k_rows(la,(b+1)/2): + for la in possible_middle_row_for_b_odd(a, c): # la is the middle row of SCPP + 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) + 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 - for PP in PPs_with_first_row_la_and_with_k_rows(la,b/2): + 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) + PP_above = complement(PP_below, c) + yield self.element_class(self, PP_above + PP_below) return def cardinality(self) -> Integer: @@ -2523,7 +2505,7 @@ def cardinality(self) -> Integer: .. MATH:: - \left(\prod_{i=1}^{r}\prod_{j=1}^{b} \frac{i + j + c - 1}{i + j - 1}\right)^2 + \left(\prod_{i=1}^{r}\prod_{j=1}^{b} \frac{i + j + c - 1}{i + j - 1}\right)^2. The number of self complementary plane partitions inside an `(2a+1) \times 2b \times 2c` box is equal to @@ -2531,8 +2513,7 @@ def cardinality(self) -> Integer: .. MATH:: \left(\prod_{i=1}^{a}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - + \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right). The number of self complementary plane partitions inside an `(2a+1) \times (2b+1) \times 2c` box is equal to @@ -2540,7 +2521,7 @@ def cardinality(self) -> Integer: .. MATH:: \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - \left(\prod_{i=1}^{a}\prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a}\prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right). EXAMPLES:: @@ -2551,59 +2532,103 @@ def cardinality(self) -> Integer: sage: P = PlanePartitions([5,4,4], symmetry='SCPP') sage: P.cardinality() 1000 + sage: P = PlanePartitions([4,5,4], symmetry='SCPP') + sage: P.cardinality() + 1000 + sage: P = PlanePartitions([4,4,5], symmetry='SCPP') + sage: P.cardinality() + 1000 sage: P = PlanePartitions([5,5,4], symmetry='SCPP') sage: P.cardinality() 2500 + sage: P = PlanePartitions([5,4,5], symmetry='SCPP') + sage: P.cardinality() + 2500 + sage: P = PlanePartitions([4,5,5], symmetry='SCPP') + sage: P.cardinality() + 2500 """ r = self._box[0] s = self._box[1] t = self._box[2] - if r % 2 == 0 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k -2 ) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) - if r % 2 == 1 and s % 2 == 0 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+t/2)))) - if r % 2 == 0 and s % 2 == 1 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) - if r % 2 == 0 and s % 2 == 0 and t % 2 == 1: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) - if r % 2 == 1 and s % 2 == 1 and t % 2 == 0: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+(s-1)/2) for k in range(1,1+t/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+t/2)))) - if r % 2 == 1 and s % 2 == 0 and t % 2 == 1: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2+1) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+(r-1)/2) for j in range(1,1+s/2) for k in range(1,1+(t-1)/2+1)))) - if r % 2 == 0 and s % 2 == 1 and t % 2 == 1: - return Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2+1) for k in range(1,1+(t-1)/2)))) * Integer((prod( Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1,1+r/2) for j in range(1,1+(s-1)/2) for k in range(1,1+(t-1)/2+1)))) - if r % 2 == 1 and s % 2 == 1 and t % 2 == 1: - return Integer(0) + if r % 2 == 0: + R = r // 2 + if s % 2 == 0: + S = s // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1))) + else: + T = (t-1) // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+2))) + else: + S = (s-1) // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+2) for k in range(1,T+1))) + else: + T = (t-1) // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+2) for k in range(1,T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+2))) + # r is odd + R = (r-1) // 2 + if s % 2 == 0: + S = s // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+2) for j in range(1,S+1) for k in range(1,T+1))) + else: + T = (t-1) // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+2) for j in range(1,S+1) for k in range(1,T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+2))) + # r and s are both odd + S = (s-1) // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+2) for j in range(1,S+1) for k in range(1,T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1,R+1) for j in range(1,S+2) for k in range(1,T+1))) + + # Should never reach here as r, s, t are all odd, which the constructor should reject + return Integer(0) # Class 6 # Transpose-complement Plane Partitions - class PlanePartitions_TCPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((3,3,2), symmetry='TCPP') -# sage: P2 = PlanePartitions([3,3,2], symmetry='TCPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_TCPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + transpose-complement. + """ def __init__(self, box_size): """ TESTS:: sage: PP = PlanePartitions([3,3,2], symmetry='TCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([3,3,3], symmetry='TCPP') Traceback (most recent call last): ... ValueError: z dimension (3) must be even + sage: PlanePartitions([4,3,2], symmetry='TCPP') Traceback (most recent call last): ... @@ -2613,9 +2638,7 @@ def __init__(self, box_size): raise ValueError("z dimension ({}) must be even".format(box_size[2])) if box_size[0] != box_size[1]: raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0],box_size[1])) - super(PlanePartitions_TCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'TCPP' + super().__init__(box_size, "TCPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -2628,8 +2651,8 @@ def _repr_(self) -> str: self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: - """ - An iterator for transpose complement plane partitions. + r""" + Iterate over all transpose complement plane partitions. EXAMPLES:: @@ -2662,39 +2685,32 @@ def cardinality(self) -> Integer: sage: P.cardinality() 5 """ - 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,1+a-2) for i in range(1,1+j))) # Class 7 # Symmetric Self-complementary Plane Partitions - class PlanePartitions_SSCPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((4,4,2), symmetry='SSCPP') -# sage: P2 = PlanePartitions([4,4,2], symmetry='SSCPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_SSCPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + symmetric self-complementary. + """ def __init__(self, box_size): """ TESTS:: - sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') + sage: PP = PlanePartitions([2,2,4], symmetry='SSCPP') sage: TestSuite(PP).run() + + sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') + sage: TestSuite(PP).run() # long time + sage: PlanePartitions([4,2,2], symmetry='SSCPP') Traceback (most recent call last): ... ValueError: x and y dimensions (4 and 2) must be equal + sage: PlanePartitions([4,4,3], symmetry='SSCPP') Traceback (most recent call last): ... @@ -2704,9 +2720,7 @@ def __init__(self, box_size): raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) if (box_size[2] % 2 == 1): raise ValueError("z dimension ({}) must be even".format(box_size[2])) - super(PlanePartitions_SSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'SSCPP' + super().__init__(box_size, "SSCPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -2720,22 +2734,21 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - An iterator for symmetric self-complementary plane partitions. + Iterate over all symmetric self-complementary plane partitions. EXAMPLES:: sage: list(PlanePartitions([4,4,2], symmetry='SSCPP')) - [Plane partition [[2, 2, 2, 1], [2, 2, 1], [2, 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, 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, 2, 2, 1], [2, 2, 1], [2, 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, 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]]] """ for p in PlanePartitions(self._box): if p.is_SSCPP(): yield self.element_class(self,p) - return def cardinality(self) -> Integer: r""" @@ -2746,14 +2759,14 @@ def cardinality(self) -> Integer: .. MATH:: - \prod_{i=1}^{a}\prod_{j=1}^{a} \frac{i + j + b - 1}{i + j - 1} + \prod_{i=1}^{a}\prod_{j=1}^{a} \frac{i + j + b - 1}{i + j - 1}. The number of symmetric self-complementary plane partitions inside a `(2a+1) \times (2a+1) \times 2b` box is equal to .. MATH:: - \prod_{i=1}^{a}\prod_{j=1}^{a+1} \frac{i + j + b - 1}{i + j - 1} + \prod_{i=1}^{a}\prod_{j=1}^{a+1} \frac{i + j + b - 1}{i + j - 1}. EXAMPLES:: @@ -2763,8 +2776,6 @@ def cardinality(self) -> Integer: sage: Q = PlanePartitions([3,3,2], symmetry='SSCPP') sage: Q.cardinality() 3 - - """ a = self._box[0] c = self._box[2] @@ -2775,32 +2786,23 @@ def cardinality(self) -> Integer: # Class 8 #Cyclically Symmetric Transpose-complement Partitions - class PlanePartitions_CSTCPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((2,2,2), symmetry='CSTCPP') -# sage: P2 = PlanePartitions([2,2,2], symmetry='CSTCPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_CSTCPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + cyclically symmetric and transpose-complement. + """ def __init__(self, box_size): """ TESTS:: sage: PP = PlanePartitions([2,2,2], symmetry='CSTCPP') sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='CSTCPP') Traceback (most recent call last): ... ValueError: x, y, and z dimensions (4,3,2) must all be equal + sage: PlanePartitions([3,3,3], symmetry='CSTCPP') Traceback (most recent call last): ... @@ -2810,9 +2812,7 @@ def __init__(self, box_size): raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) if box_size[0] % 2 == 1: raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) - super(PlanePartitions_CSTCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'CSTCPP' + super().__init__(box_size, "CSTPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -2826,7 +2826,7 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - An iterator for cyclically symmetry transpose complement plane partitions. + Iterate over all cyclically symmetry transpose complement plane partitions. EXAMPLES:: @@ -2836,7 +2836,6 @@ def __iter__(self) -> Iterator: for p in PlanePartitions(self._box): if p.is_CSTCPP(): yield self.element_class(self,p) - return def cardinality(self) -> Integer: r""" @@ -2855,27 +2854,16 @@ def cardinality(self) -> Integer: sage: P.cardinality() 11 """ - a = self._box[0] - return Integer(prod( ((3*i+1)*factorial(6*i)*factorial(2*i))/(factorial(4*i+1)*factorial(4*i)) for i in range((a/2)))) + 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))) # Class 9 # Cyclically Symmetric Self-complementary Plane Partitions - class PlanePartitions_CSSCPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((4,4,4), symmetry='CSSCPP') -# sage: P2 = PlanePartitions([4,4,4], symmetry='CSSCPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_CSSCPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + cyclically symmetric self-complementary. + """ def __init__(self, box_size): """ TESTS:: @@ -2895,9 +2883,7 @@ def __init__(self, box_size): raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) if box_size[0] % 2 == 1: raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) - super(PlanePartitions_CSSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'CSSCPP' + super().__init__(box_size, "CSSCPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -2911,7 +2897,7 @@ def _repr_(self) -> str: def __iter__(self) -> Iterator: """ - An iterator for cyclically symmetric self-complementary plane partitions. + Iterate over all cyclically symmetric self-complementary plane partitions. EXAMPLES:: @@ -2921,7 +2907,6 @@ def __iter__(self) -> Iterator: for p in PlanePartitions(self._box): if p.is_CSSCPP(): yield self.element_class(self,p) - return def cardinality(self) -> Integer: r""" @@ -2940,27 +2925,16 @@ def cardinality(self) -> Integer: sage: P.cardinality() 49 """ - a = self._box[0] - return Integer(prod( ((factorial(3*i+1)**2/(factorial(a/2+i)**2) for i in range((a/2)))))) + a = self._box[0] // 2 + return Integer(prod(factorial(3*i+1)**2 / factorial(a+i)**2 for i in range(a))) # Class 10 # Totally Symmetric Self-complementary Plane Partitions - class PlanePartitions_TSSCPP(PlanePartitions): -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((4,4,4), symmetry='TSSCPP') -# sage: P2 = PlanePartitions([4,4,4], symmetry='TSSCPP') -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_TSSCPP, cls).__classcall__(cls, tuple(box_size)) - + r""" + Plane partitions that fit inside a box of a specified size that are + totally symmetric self-complementary. + """ def __init__(self, box_size): """ TESTS:: @@ -2980,12 +2954,10 @@ def __init__(self, box_size): raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) if box_size[0] % 2 == 1: raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) - super(PlanePartitions_TSSCPP, self).__init__(category=FiniteEnumeratedSets()) - self._box = box_size - self._symmetry = 'TSSCPP' + super().__init__(box_size, "TSSCPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: - """ + r""" EXAMPLES:: sage: PlanePartitions([4,4,4], symmetry='TSSCPP') @@ -3007,21 +2979,20 @@ def to_poset(self): sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ - def comp(x,y): return(all(x[i] <= y[i] for i in range(len(x)))) + from sage.combinat.posets.posets import Poset a = self._box[0] b = self._box[1] c = self._box[2] if a != b or b != c or a != c: - return + return Poset() - pl = [] - for x in range(0,a/2 - 2 + 1): - for y in range(x, a/2 - 2 + 1): - for z in range(0,a/2 - 2 + 1): - if z <= a/2 - 2 - y: - pl.append((x,y,z)) + def comp(x, y): + return all(xx <= yy for xx, yy in zip(x, y)) - return Poset((pl,comp)) + A = a // 2 + pl = [(x,y,z) for x in range(A-1) for y in range(x, A-1) + for z in range(A-1) if z <= A - 2 - y] + return Poset((pl, comp)) def from_antichain(self, acl) -> PP: r""" @@ -3040,31 +3011,32 @@ def from_antichain(self, acl) -> PP: b = self._box[1] c = self._box[2] n = a + N = n // 2 ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane parition populated by 0s #EX: [[0,0,0], [0,0,0], [0,0,0]] - width = n/2 - 1 - height = n/2 - 1 + width = N - 1 + height = N - 1 - #generate inner triangle + # generate inner triangle + # FIXME: Make this ierator more efficient for i in range(width): - for j in range(height): - if(i <= j): - for ac in acl: - if ac[0] == i and ac[1] == j: - zVal = ac[2] - matrixVal = ppMatrix[j +(n/2)] [i+ (n/2)] - if zVal + 1 > matrixVal: - ppMatrix[j +(n/2)] [i+ (n/2)]= zVal + 1 - - #fill back + for j in range(min(height, i+1)): + for ac in acl: + if ac[0] == i and ac[1] == j: + zVal = ac[2] + matrixVal = ppMatrix[j+N][i+N] + if zVal + 1 > matrixVal: + ppMatrix[j+N][i+N] = zVal + 1 + + # fill back for i in range(width): - i = width-(i+1) - i = i + n/2 + i = width - (i + 1) + i = i + N for j in range(height): - j = height-(j+1) - j = j + n/2 - if (ppMatrix[i][j] == 0): + j = height - (j + 1) + j = j + N + if ppMatrix[i][j] == 0: if i >= j: iValue = 0 jValue = 0 @@ -3076,44 +3048,44 @@ def from_antichain(self, acl) -> PP: #fill half of triangle symmetrically for i in range(width): - i = i + n/2 + i += N for j in range(height): - j = j + n/2 + j += N if i >= j: ppMatrix[j][i] = ppMatrix[i][j] #upper left box - for i in range(n/2): - for j in range(n/2): + for i in range(N): + for j in range(N): ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] #fill in lower left cube with values n/2 - for i in range(n/2): - for j in range(n/2): + for i in range(N): + for j in range(N): x = i y = j - if(ppMatrix[x][y+(n/2)]) == 0: - ppMatrix[x][y+(n/2)] = n/2 - if(ppMatrix[x+(n/2)][y]) == 0: - ppMatrix[x+(n/2)][y] = n/2 + if ppMatrix[x][y+N] == 0: + ppMatrix[x][y+N] = N + if ppMatrix[x+N][y] == 0: + ppMatrix[x+N][y] = N #add and subtract values from lower left cube to be rotation of lower right cube - for i in range(n/2): - for j in range(n/2): - x = i+(n/2) - y = j+(n/2) + for i in range(N): + for j in range(N): + x = i + N + y = j + N if ppMatrix[x][y] > 0: z = ppMatrix[x][y] for cVal in range(z): #build onto lower left cube ppMatrix[x][0+cVal] += 1 #carve out of lower left cube - ppMatrix[n-(1+cVal)][(n/2)-(j+1)] -=1 + ppMatrix[n-(1+cVal)][N-(j+1)] -= 1 #fill in upper right cube symmetrically with lower left - for i in range(n/2): - for j in range(n/2): - ppMatrix[j][i+(n/2)] = ppMatrix[i+(n/2)][j] + for i in range(N): + for j in range(N): + ppMatrix[j][i+N] = ppMatrix[i+N][j] return self.element_class(self, ppMatrix) def from_order_ideal(self, I) -> PP: @@ -3132,7 +3104,7 @@ def from_order_ideal(self, I) -> PP: def __iter__(self) -> Iterator: """ - An iterator for totally symmetric self-complementary plane partitions. + Iterate over all totally symmetric self-complementary plane partitions. EXAMPLES:: @@ -3153,7 +3125,7 @@ def cardinality(self) -> Integer: .. MATH:: - \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!} + \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}. EXAMPLES:: @@ -3161,5 +3133,6 @@ def cardinality(self) -> Integer: sage: P.cardinality() 7 """ - a = self._box[0] - return Integer(prod( ((factorial(3*i+1)/(factorial(a/2+i)) for i in range((a/2)))))) + a = self._box[0] // 2 + return Integer(prod(factorial(3*i+1) / factorial(a+i) for i in range(a))) + From 7adbc63792a0f5763c419c415636d1af3ba67c5d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 13 Feb 2023 17:16:03 +0900 Subject: [PATCH 72/74] Fixing some details, docstrings, and code format. --- src/sage/combinat/all.py | 1 + src/sage/combinat/plane_partition.py | 770 ++++++++++++++------------- 2 files changed, 394 insertions(+), 377 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index de539d5ec5f..47cd721e0a5 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -194,6 +194,7 @@ # Plane Partitions lazy_import('sage.combinat.plane_partition', ('PlanePartition', 'PlanePartitions')) + # Parking Functions lazy_import('sage.combinat.non_decreasing_parking_function', ['NonDecreasingParkingFunctions', 'NonDecreasingParkingFunction']) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 638b43624e7..811b9365400 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Plane Partitions @@ -44,10 +43,10 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers -#from sage.categories.sets_cat import Sets PP = NewType('PP', 'PlanePartition') + @richcmp_method class PlanePartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): @@ -59,7 +58,6 @@ class PlanePartition(ClonableArray, INPUT: - ``PP`` -- a list of lists which represents a tableau - - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, `y`-axis, `z`-axis, respectively; if this is not given, it is @@ -119,7 +117,6 @@ def __init__(self, parent, pp, check=True): True sage: a is c False - """ if isinstance(pp, PlanePartition): ClonableArray.__init__(self, parent, pp, check=False) @@ -130,7 +127,7 @@ def __init__(self, parent, pp, check=True): while pp[i] and not pp[i][-1]: del pp[i][-1] if not pp[i]: - pp.pop(i) + pp.pop(i) ClonableArray.__init__(self, parent, pp, check=check) if self.parent()._box is None: if pp: @@ -162,11 +159,11 @@ def __richcmp__(self, other, op): INPUT: - ``other`` -- the element that ``self`` is compared to + - ``other`` -- the element that ``self`` is compared to OUTPUT: - A Boolean. + A boolean. TESTS:: @@ -188,9 +185,9 @@ def __richcmp__(self, other, op): True """ if isinstance(other, PlanePartition): - return richcmp(list(self), list(other), op) - else: - return richcmp(list(self), other, op) + return self._richcmp_(other, op) + + return richcmp(list(self), other, op) def check(self): """ @@ -202,7 +199,7 @@ def check(self): sage: a.check() sage: b = PlanePartition([[1,2],[1]]) Traceback (most recent call last): - ... + ... ValueError: not weakly decreasing along rows sage: c = PlanePartition([[1,1],[2]]) Traceback (most recent call last): @@ -257,8 +254,8 @@ def z_tableau(self, tableau=True) -> Tableau: Return the projection of ``self`` in the `z` direction. If ``tableau`` is set to ``False``, then only the list of lists - consisting of the projection of boxes size onto the xy-plane - is returned instead of a Tableau object. This output will + consisting of the projection of boxes size onto the `xy`-plane + is returned instead of a :class:`Tableau` object. This output will not have empty trailing rows or trailing zeros removed. EXAMPLES:: @@ -279,8 +276,8 @@ def y_tableau(self, tableau=True) -> Tableau: Return the projection of ``self`` in the `y` direction. If ``tableau`` is set to ``False``, then only the list of lists - consisting of the projection of boxes size onto the xz-plane - is returned instead of a Tableau object. This output will + consisting of the projection of boxes size onto the `xz`-plane + is returned instead of a :class:`Tableau` object. This output will not have empty trailing rows or trailing zeros removed. EXAMPLES:: @@ -301,8 +298,8 @@ def x_tableau(self, tableau=True) -> Tableau: Return the projection of ``self`` in the `x` direction. If ``tableau`` is set to ``False``, then only the list of lists - consisting of the projection of boxes size onto the yz-plane - is returned instead of a Tableau object. This output will + consisting of the projection of boxes size onto the `yz`-plane + is returned instead of a :class:`Tableau` object. This output will not have empty trailing rows or trailing zeros removed. EXAMPLES:: @@ -615,7 +612,6 @@ def _latex_(self, show_box=False, - ``show_box`` -- boolean (default: ``False``); if ``True``, also shows the visible tiles on the `xy`-, `yz`-, `zx`-planes - - ``colors`` -- (default: ``["white", "lightgray", "darkgray"]``) list ``[A, B, C]`` of 3 strings representing colors @@ -668,7 +664,6 @@ def plot(self, show_box=False, colors=None): - ``show_box`` -- boolean (default: ``False``); if ``True``, also shows the visible tiles on the `xy`-, `yz`-, `zx`-planes - - ``colors`` -- (default: ``["white", "lightgray", "darkgray"]``) list ``[A, B, C]`` of 3 strings representing colors @@ -725,9 +720,9 @@ def add_rightside(i, j, k): TP += add_leftside(self.x_tableau()[r][c], r, c) TP.axes(show=False) return TP - + def contains(self, PP) -> bool: - """ + r""" Return ``True`` if ``PP`` is a plane partition that fits inside ``self``. @@ -737,9 +732,9 @@ def contains(self, PP) -> bool: EXAMPLES:: - sage: P1 = PlanePartition([[5,4,3],[3,2,2],[1]]) - sage: P2 = PlanePartition([[3,2],[1,1],[0,0],[0,0]]) - sage: P3 = PlanePartition([[5,5,5],[2,1,0]]) + sage: P1 = PlanePartition([[5,4,3], [3,2,2], [1]]) + sage: P2 = PlanePartition([[3,2], [1,1], [0,0], [0,0]]) + sage: P3 = PlanePartition([[5,5,5], [2,1,0]]) sage: P1.contains(P2) True sage: P2.contains(P1) @@ -749,13 +744,16 @@ def contains(self, PP) -> bool: sage: P3.contains(P2) True """ - PP = PlanePartition(PP) + if not isinstance(PP, PlanePartition): + PP = PlanePartition(PP) if len(self) < len(PP): return False - for i in range(len(PP)): - if len(self[i]) < len(PP[i]): + for rowself, rowPP in zip(self, PP): + if len(rowself) < len(rowPP): return False - return all(self[i][j] >= PP[i][j] for i,row in enumerate(PP) for j in range(len(row))) + if any(valself < valPP for valself, valPP in zip(rowself, rowPP)): + return False + return True def plot3d(self, colors=None): r""" @@ -789,8 +787,8 @@ def complement(self, tableau_only=False) -> PP: The empty plane partition with no box specified is its own complement. If ``tableau_only`` is set to ``True``, then only the tableau - consisting of the projection of boxes size onto the xy-plane - is returned instead of a PlanePartition object. This output will + consisting of the projection of boxes size onto the `xy`-plane + is returned instead of a :class:`PlanePartition`. This output will not have empty trailing rows or trailing zeros removed. EXAMPLES:: @@ -808,25 +806,24 @@ def complement(self, tableau_only=False) -> PP: z_tab = self.z_tableau() for r in range(A): for c in range(B): - T[A - 1 - r][B - 1 - c] = C - z_tab[r][c] + T[A-1-r][B-1-c] = C - z_tab[r][c] if tableau_only: return T - elif not self.parent()._box: + P = self.parent() + if not P._box: pp = PlanePartitions() return pp.element_class(pp, T) - else: - return type(self)(self.parent(), T, check=False) + return P.element_class(P, T, check=False) def transpose(self, tableau_only=False) -> PP: r""" Return the transpose of ``self``. If ``tableau_only`` is set to ``True``, then only the tableau - consisting of the projection of boxes size onto the xy-plane - is returned instead of a PlanePartition object. This will + consisting of the projection of boxes size onto the `xy`-plane + is returned instead of a :class:`PlanePartition`. This will not necessarily have trailing rows or trailing zeros removed. - EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -834,18 +831,27 @@ def transpose(self, tableau_only=False) -> PP: Plane partition [[4, 2, 1], [3, 1, 1], [3, 1], [1]] sage: PP.transpose(True) [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] + + sage: PPP = PlanePartitions([1, 2, 3]) + sage: PP = PPP([[1, 1]]) + sage: PT = PP.transpose(); PT + Plane partition [[1], [1]] + sage: PT.parent() + Plane partitions inside a 2 x 1 x 3 box """ T = [[0 for i in range(self._max_x)] for j in range(self._max_y)] z_tab = self.z_tableau() for r in range(len(z_tab)): for c in range(len(z_tab[r])): T[c][r] = z_tab[r][c] + P = self.parent() if tableau_only: return T - elif self.parent()._box is None or self.parent()._box[0] == self.parent()._box[1]: - return type(self)(self.parent(), T, check=False) - new_box = (self.parent()._box[1],self.parent()._box[0],self.parent()._box[2]) - return PlanePartitions(new_box,symmetry=self.parent._symmetry) + elif P._box is None or P._box[0] == P._box[1]: + return P.element_class(P, T, check=False) + new_box = (P._box[1], P._box[0], P._box[2]) + newP = PlanePartitions(new_box, symmetry=P._symmetry) + return newP.element_class(newP, T) def is_SPP(self) -> bool: r""" @@ -928,12 +934,12 @@ def is_TSPP(self) -> bool: def is_SCPP(self) -> bool: r""" Return whether ``self`` is a self-complementary plane partition. - + Note that the complement of a plane partition (and thus the property of - being self-complementary) is dependent on the choice of a box that it is - contained in. If no parent/bounding box is specified, the box is taken + being self-complementary) is dependent on the choice of a box that it is + contained in. If no parent/bounding box is specified, the box is taken to be the smallest box that contains the plane partition. - + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -1036,14 +1042,16 @@ def is_TSSCPP(self) -> bool: """ return self.is_TSPP() and self.is_SCPP() - def to_order_ideal(self): - """ + def to_order_ideal(self): + r""" Return the order ideal corresponding to ``self``. - TODO: As many families of symmetric plane partitions are in bijection - with order ideals in an associated poset, this function could - feasibly have options to send symmetric plane partitions - to the associated order ideal in that poset, instead. + .. TODO:: + + As many families of symmetric plane partitions are in bijection + with order ideals in an associated poset, this function could + feasibly have options to send symmetric plane partitions + to the associated order ideal in that poset, instead. EXAMPLES:: @@ -1054,13 +1062,13 @@ def to_order_ideal(self): """ from sage.combinat.posets.poset_examples import posets (a, b, c) = (self._max_x, self._max_y, self._max_z) - Q = posets.ProductOfChains([a,b,c]) + Q = posets.ProductOfChains([a, b, c]) count = 0 generate = [] - for i in range(len(self)): - for j in range(len(self[i])): - if (self[i][j] > 0): - generate.append((i,j,self[i][j]-1)) + for i, row in enumerate(self): + for j, val in enumerate(row): + if val > 0: + generate.append((i, j, val-1)) count += 1 oi = Q.order_ideal(generate) return oi @@ -1080,10 +1088,10 @@ def maximal_boxes(self) -> list: [[0, 0, 1], [0, 1, 0], [2, 0, 0]] """ generate = [] - for i,row in enumerate(self): - for j,entry in enumerate(row): + for i, row in enumerate(self): + 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]) + generate.append([i, j, entry-1]) return(generate) def cyclically_rotate(self, preserve_parent=False) -> PP: @@ -1091,11 +1099,11 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: Return the cyclic rotation of ``self``. By default, if the parent of ``self`` consists of plane - partitions inside an `a \times b \times c` box, the result + partitions inside an `a \times b \times c` box, the result will have a parent consisting of partitions inside a `c \times a \times b` box, unless the optional parameter ``preserve_parent`` is set to ``True``. Enabling this setting - may give an element that is NOT an element of its parent. + may give an element that is **not** an element of its parent. EXAMPLES:: @@ -1114,37 +1122,38 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: sage: PP_rotated in PP_rotated.parent() False """ - b = self._max_y + b = self._max_y c = self._max_z new_antichain = [] for elem in self.maximal_boxes(): new = (elem[1], elem[2], elem[0]) new_antichain.append(new) - ppMatrix = [[0] * (c) for i in range(b)] + pp_matrix = [[0] * (c) for i in range(b)] for box in new_antichain: y = box[0] z = box[1] x = box[2] - ppMatrix[y][z] = x + 1 + pp_matrix[y][z] = x + 1 if new_antichain: for i in range(b): i = b - (i+1) for j in range(c): j = c - (j+1) - if (ppMatrix[i][j] == 0): + if pp_matrix[i][j] == 0: iValue = 0 jValue = 0 if i < b-1: - iValue = ppMatrix[i+1][j] + iValue = pp_matrix[i+1][j] if j < c-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) # Start code for determining correct parent P = self.parent() if P._box is None or preserve_parent or (P._box[0] == P._box[1] == P._box[2]): - return type(self)(P, ppMatrix, check=False) + return P.element_class(P, pp_matrix, check=preserve_parent) new_box = (P._box[2], P._box[0], P._box[1]) - return PlanePartitions(new_box,symmetry=P._symmetry)(ppMatrix) + newP = PlanePartitions(new_box, symmetry=P._symmetry) + return newP.element_class(newP, pp_matrix) def bounding_box(self): r""" @@ -1160,7 +1169,6 @@ def bounding_box(self): return (0, 0, 0) return (len(self), len(self[0]), self[0][0]) -#PP = PlanePartition class PlanePartitions(UniqueRepresentation, Parent): r""" @@ -1171,53 +1179,53 @@ class PlanePartitions(UniqueRepresentation, Parent): ``PlanePartitions(n)`` return the class of all plane partitions with precisely `n` boxes. - ``PlanePartitions([a,b,c]) returns the class of plane partitions that fit - inside an `a \times b \times c` box. + ``PlanePartitions([a, b, c])`` returns the class of plane partitions + that fit inside an `a \times b \times c` box. - ``PlanePartitions([a,b,c])`` has the optional keyword ``symmetry``, which + ``PlanePartitions([a, b, c])`` has the optional keyword ``symmetry``, which restricts the plane partitions inside a box of the specified size satisfying certain symmetry conditions. - - ``symmetry = 'SPP'`` gives the class of symmetric plane partitions. which + - ``symmetry='SPP'`` gives the class of symmetric plane partitions. which is all plane partitions fixed under reflection across the diagonal. Requires that `a = b`. - - ``symmetry = 'CSPP'`` gives the class of cyclic plane partitions, which + - ``symmetry='CSPP'`` gives the class of cyclic plane partitions, which is all plane partitions fixed under cyclic rotation of coordinates. Requires that `a = b = c`. - - ``symmetry = 'TSPP'`` gives the class of totally symmetric plane partitions, + - ``symmetry='TSPP'`` gives the class of totally symmetric plane partitions, which is all plane partitions fixed under any interchanging of coordinates. Requires that `a = b = c`. - - ``symmetry = 'SCPP'`` gives the class of self-complementary plane partitions. + - ``symmetry='SCPP'`` gives the class of self-complementary plane partitions. which is all plane partitions that are equal to their own complement in the specified box. Requires at least one of `a,b,c` be even. - - ``symmetry = 'TCPP'`` gives the class of transpose complement plane partitions, - which is all plane partitions whose complement in the box of the specified - size is equal to their transpose. Requires `a = b` and at least one of - `a,b,c` be even. + - ``symmetry='TCPP'`` gives the class of transpose complement plane + partitions, which is all plane partitions whose complement in the box + of the specified size is equal to their transpose. Requires `a = b` and + at least one of `a, b, c` be even. - - ``symmetry = 'SSCPP'`` gives the class of symmetric self-complementary + - ``symmetry='SSCPP'`` gives the class of symmetric self-complementary plane partitions, which is all plane partitions that are both symmetric and self-complementary. Requires `a = b` and at least one of - `a,b,c` be even. + `a, b, c` be even. - - ``symmetry = 'CSTCPP'`` gives the class of cyclically symmetric transpose + - ``symmetry='CSTCPP'`` gives the class of cyclically symmetric transpose complement plane partitions, which is all plane partitions that are both symmetric and equal to the transpose of their complement. Requires `a = b = c`. - - ``symmetry = 'CSSCPP'`` gives the class of cyclically symmetric + - ``symmetry='CSSCPP'`` gives the class of cyclically symmetric self-complementary plane partitions, which is all plane partitions that are both cyclically symmetric and self-complementary. Requires `a = b = c` - and at least one of `a,b,c` be even. + and all `a, b, c` be even. - - ``symmetry = 'TSSCPP'`` gives the class of totally symmetric + - ``symmetry='TSSCPP'`` gives the class of totally symmetric self-complementary plane partitions, which is all plane partitions that are totally symmetric and also self-complementary. Requires `a = b = c` - and at least one of `a,b,c` be even. + and all `a, b, c` be even. EXAMPLES: @@ -1243,7 +1251,7 @@ class PlanePartitions(UniqueRepresentation, Parent): Plane partition [[1], [1], [1]]] If a three-element tuple or list `[a,b,c]` is passed, then the class of all - plane partitions that fit inside and `a\times b\times c` box is returned:: + plane partitions that fit inside and `a \times b \times c` box is returned:: sage: PlanePartitions([2,2,2]) Plane partitions inside a 2 x 2 x 2 box @@ -1251,7 +1259,7 @@ class PlanePartitions(UniqueRepresentation, Parent): True If an additional keyword ``symmetry`` is pass along with a three-element - tuple or list `[a,b,c]`, then the class of all plane partitions that fit + tuple or list `[a, b,c ]`, then the class of all plane partitions that fit inside an `a \times b \times c` box with the specified symmetry is returned:: sage: PlanePartitions([2,2,2], symmetry='CSPP') @@ -1274,7 +1282,6 @@ class PlanePartitions(UniqueRepresentation, Parent): - :class:`PlanePartitions_CSTCPP` - :class:`PlanePartitions_CSSCPP` - :class:`PlanePartitions_TSSCPP` - """ @staticmethod def __classcall_private__(cls, *args, **kwds): @@ -1359,7 +1366,7 @@ def __contains__(self, pp): sage: [[3,2,1],[1,2]] in PlanePartitions() False sage: [[3,2,1],[3,3]] in PlanePartitions() - False + False """ if isinstance(pp, PlanePartition): return True @@ -1411,6 +1418,7 @@ def symmetry(self) -> str: """ return self._symmetry + class PlanePartitions_all(PlanePartitions, DisjointUnionEnumeratedSets): r""" All plane partitions. @@ -1434,7 +1442,7 @@ def __init__(self): # This is so DisjointUnionEnumeratedSets can make the Parent.__init__() call. self._box = None self._symmetry = None - #super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) + # super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), PlanePartitions_n), @@ -1463,31 +1471,18 @@ def an_element(self): """ return self.element_class(self, [[2, 1], [1]]) + class PlanePartitions_box(PlanePartitions): r""" All plane partitions that fit inside a box of a specified size. By convention, a plane partition in an `a \times b \times c` box - will have at most 'a' rows, of lengths at most 'b', with entries - at most 'c'. + will have at most `a` rows, of lengths at most `b`, with entries + at most `c`. """ -# @staticmethod -# def __classcall_private__(cls, box_size): -# """ -# Normalize input to ensure a unique representation. - -# EXAMPLES:: - -# sage: P1 = PlanePartitions((4,3,2)) -# sage: P2 = PlanePartitions([4,3,2]) -# sage: P1 is P2 -# True -# """ -# return super(PlanePartitions_box, cls).__classcall__(cls, tuple(box_size)) - def __init__(self, box_size): r""" - Initializes the class of plane partitions that fit in a box of a + Initializes the class of plane partitions that fit in a box of a specified size. EXAMPLES:: @@ -1537,10 +1532,10 @@ def to_poset(self): Finite lattice containing 8 elements """ a = self._box[0] - b = self._box[1] + b = self._box[1] c = self._box[2] from sage.combinat.posets.poset_examples import posets - return posets.ProductOfChains([a,b,c]) + return posets.ProductOfChains([a, b, c]) def from_order_ideal(self, I) -> PP: r""" @@ -1568,32 +1563,33 @@ def from_antichain(self, A) -> PP: """ a = self._box[0] b = self._box[1] - ppMatrix = [[0] * (b) for i in range(a)] #creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + # Creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + pp_matrix = [[0] * (b) for i in range(a)] - #ac format ex: [x,y,z] - #iterate through each antichain, assigning the y,z position in ppMatrix = the height of the stack (x + 1) + # ac format ex: [x,y,z] + # iterate through each antichain, assigning the y,z position in pp_matrix = the height of the stack (x + 1) for ac in A: x = ac[0] y = ac[1] z = ac[2] - ppMatrix[x][y] = (z+1) + pp_matrix[x][y] = z + 1 - #for each value in current antichain, fill in the rest of the matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format + # For each value in current antichain, fill in the rest of the matrix by + # rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format if A: for i in range(a): - i = a-(i+1) + i = a - (i + 1) for j in range(b): - j = b-(j+1) - if (ppMatrix[i][j] == 0): + j = b - (j + 1) + if pp_matrix[i][j] == 0: iValue = 0 jValue = 0 if i < a-1: - iValue = ppMatrix[i+1][j] + iValue = pp_matrix[i+1][j] if j < b-1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) - return self.element_class(self, ppMatrix) - + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + return self.element_class(self, pp_matrix) def __iter__(self) -> Iterator: r""" @@ -1660,6 +1656,7 @@ def random_element(self) -> PP: Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) + class PlanePartitions_n(PlanePartitions): """ Plane partitions with a fixed number of boxes. @@ -1671,7 +1668,7 @@ def __init__(self, n): .. WARNING:: Input is not checked; please use :class:`PlanePartitions` to - ensure the options are properly parsed. (CHECK: does this make sense?) + ensure the options are properly parsed. TESTS:: @@ -1701,7 +1698,7 @@ def __contains__(self, x) -> bool: sage: [[2,1],[1]] in PlanePartitions(3) False """ - return PlanePartitions.__contains__(self, x) and PlanePartition(x).number_of_boxes() == self._n + return PlanePartitions.__contains__(self, x) and PlanePartition(x).number_of_boxes() == self._n def __iter__(self) -> Iterator: r""" @@ -1716,7 +1713,6 @@ def __iter__(self) -> Iterator: def P_in_shape_iter(n, la): if n < 0 or sum(la) < n: - yield return if n == 0: yield [] @@ -1724,44 +1720,37 @@ def P_in_shape_iter(n, la): if len(la) == 1: if la[0] >= n: yield [n] - return - else: - yield - return + return if sum(la) == n: yield la return - for mu_0 in range(min(n,la[0]),0,-1): - new_la = [min(mu_0,la[i]) for i in range(1,len(la))] + for mu_0 in range(min(n, la[0]), 0, -1): + new_la = [min(mu_0, la[i]) for i in range(1, len(la))] for mu in P_in_shape_iter(n-mu_0, new_la): - if mu is not None: - yield [mu_0]+mu + yield [mu_0] + mu def PP_first_row_iter(n, la): - m = n-sum(la) + m = n - sum(la) if m < 0: - yield return if m == 0: yield [la] return - for k in range(m,0,-1): - for mu in P_in_shape_iter(k,la): - if mu is not None: - for PP in PP_first_row_iter(m, mu): - if PP is not None: - yield [la] + PP + for k in range(m, 0, -1): + for mu in P_in_shape_iter(k, la): + for PP in PP_first_row_iter(m, mu): + yield [la] + PP n = self._n - if n == 0: + if not n: yield PlanePartition([]) return - for m in range(n,0,-1): + for m in range(n, 0, -1): for la in Partitions(m): - for a in PP_first_row_iter(n,la): + for a in PP_first_row_iter(n, la): yield self.element_class(self, a, check=False) - + def cardinality(self) -> Integer: r""" Return the number of plane partitions with ``n`` boxes. @@ -1770,10 +1759,10 @@ def cardinality(self) -> Integer: .. MATH:: - PL(n) = \sum_{k=1}^n PL(n-k)\sigma_2(k) + PL(n) = \sum_{k=1}^n PL(n-k) \sigma_2(k), - where `\sigma_k(n)` is the sum of the kth powers of - divisors of n. + where `\sigma_k(n)` is the sum of the `k`-th powers of + divisors of `n`. EXAMPLES:: @@ -1783,10 +1772,11 @@ def cardinality(self) -> Integer: """ PPn = [1] - for i in range(1,1+self._n): - nextPPn = sum(PPn[i-k]*Sigma()(k,2) for k in range(1,i+1))/i + for i in range(1, 1+self._n): + nextPPn = sum(PPn[i-k] * Sigma()(k, 2) for k in range(1, i+1)) / i PPn.append(nextPPn) - return(Integer(PPn[-1])) + return Integer(PPn[-1]) + # Symmetry classes are enumerated and labelled in order as in Proofs and # Confirmations/Stanley (with all plane partitions being the first class) @@ -1800,6 +1790,8 @@ class PlanePartitions_SPP(PlanePartitions): """ def __init__(self, box_size): """ + Initialize ``self``. + TESTS:: sage: PP = PlanePartitions([3,3,2], symmetry='SPP') @@ -1836,7 +1828,9 @@ def __contains__(self, x) -> bool: """ P = PlanePartition(x) max = (P._max_x, P._max_y, P._max_z) - return PlanePartitions.__contains__(self, x) and P.is_SPP() and all( a<=b for a,b in zip(max,self._box)) + return (PlanePartitions.__contains__(self, x) + and P.is_SPP() + and all(a <= b for a, b in zip(max, self._box))) def to_poset(self): r""" @@ -1851,19 +1845,19 @@ def to_poset(self): sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() True """ - a = self._box[0] + a = self._box[0] c = self._box[2] - def comp(x,y): - return all(a <= b for a,b in zip(x, y)) + def comp(x, y): + return all(a <= b for a, b in zip(x, y)) - pl = [(x,y,z) for x in range(a) for y in range(x+1) for z in range(c)] + pl = [(x, y, z) for x in range(a) for y in range(x+1) for z in range(c)] from sage.combinat.posets.posets import Poset - return Poset((pl,comp)) + return Poset((pl, comp)) def from_order_ideal(self, I) -> PP: r""" - Return the symmetric plane partition corresponding to an order ideal + Return the symmetric plane partition corresponding to an order ideal in the poset given in :meth:`to_poset()`. EXAMPLES:: @@ -1877,7 +1871,7 @@ def from_order_ideal(self, I) -> PP: def from_antichain(self, A) -> PP: r""" - Return the symmetric plane partition corresponding to an antichain + Return the symmetric plane partition corresponding to an antichain in the poset given in :meth:`to_poset()`. EXAMPLES:: @@ -1887,35 +1881,34 @@ def from_antichain(self, A) -> PP: sage: PP.from_antichain(A) Plane partition [[2, 2, 1], [2, 1, 1], [1, 1, 1]] """ - #Initialize an empty plane partition + # Initialize an empty plane partition a = self._box[0] b = self._box[1] - ppMatrix = [[0] * (b) for i in range(a)] - #Antichain indicates where the 'corners' will be in the - #plane partition + pp_matrix = [[0] * (b) for i in range(a)] + # Antichain indicates where the 'corners' will be in the plane partition for ac in A: x = ac[0] y = ac[1] z = ac[2] - ppMatrix[x][y] = z + 1 - #Fill out the rest of the plane partition using symmetry and the - #rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) + pp_matrix[x][y] = z + 1 + # Fill out the rest of the plane partition using symmetry and the + # rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) if A: for i in range(a): - i = a-(i+1) + i = a - (i + 1) for j in range(b): - j = b-(j+1) - if ppMatrix[i][j] == 0 and i >= j: + j = b - (j + 1) + if pp_matrix[i][j] == 0 and i >= j: iValue = 0 jValue = 0 if i < a - 1: - iValue = ppMatrix[i+1][j] + iValue = pp_matrix[i+1][j] if j < b - 1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue, jValue) - elif j>i: - ppMatrix[i][j] = ppMatrix[j][i] - return self.element_class(self, ppMatrix) + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + elif j > i: + pp_matrix[i][j] = pp_matrix[j][i] + return self.element_class(self, pp_matrix) def __iter__(self) -> Iterator: """ @@ -1941,8 +1934,8 @@ def cardinality(self) -> Integer: .. MATH:: - \left(\prod_{i=1}^{a} \frac{2i + b - 1}{2i - 1}\right) - \left(\prod_{1 \leq i < j \leq a} \frac{i+j+b-1}{i+j-1}\right) + \left(\prod_{i=1}^{a} \frac{2i + b - 1}{2i - 1}\right) + \left(\prod_{1 \leq i < j \leq a} \frac{i+j+b-1}{i+j-1}\right). EXAMPLES:: @@ -1952,11 +1945,11 @@ def cardinality(self) -> Integer: """ a = self._box[0] c = self._box[2] - leftProduct = (prod( (2*i + c - 1) / (2*i - 1) for i in range(1,a+1))) - rightProduct = (prod( (i + j + c - 1) / (i + j - 1) - for j in range(1, a+1) - for i in range(1, j) )) - return Integer(leftProduct * rightProduct) + 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) def random_element(self) -> PP: r""" @@ -1988,8 +1981,10 @@ class PlanePartitions_CSPP(PlanePartitions): """ def __init__(self, box_size): """ + Initialize ``self``. + TESTS:: - + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') sage: TestSuite(PP).run() sage: PlanePartitions([4,3,2], symmetry='CSPP') @@ -1998,7 +1993,7 @@ def __init__(self, box_size): ValueError: x, y, and z dimensions (4,3,2) must all be equal """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) super().__init__(box_size, "CSPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: @@ -2024,11 +2019,13 @@ def __contains__(self, x) -> bool: """ P = PlanePartition(x) max = (P._max_x, P._max_y, P._max_z) - return PlanePartitions.__contains__(self, x) and P.is_CSPP() and all( a<=b for a,b in zip(max,self._box)) + return (PlanePartitions.__contains__(self, x) + and P.is_CSPP() + and all(a <= b for a, b in zip(max, self._box))) def to_poset(self): """ - Return a partially ordered set whose order ideals are in bijection with + Return a partially ordered set whose order ideals are in bijection with cyclically symmetric plane partitions. EXAMPLES:: @@ -2037,7 +2034,7 @@ def to_poset(self): sage: PP.to_poset() Finite poset containing 11 elements sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() - True + True """ a = self._box[0] b = self._box[1] @@ -2047,16 +2044,16 @@ def comp(x, y): return all(a <= b for a, b in zip(x, y)) def comp2(x, y): - return(comp(x, y) or comp(x, (y[2],y[0],y[1])) or comp(x, (y[1],y[2],y[0]))) + return comp(x, y) or comp(x, (y[2], y[0], y[1])) or comp(x, (y[1], y[2], y[0])) - pl = [(x,y,z) for x in range(a) for y in range(b) for z in range(x,c) + pl = [(x, y, z) for x in range(a) for y in range(b) for z in range(x, c) if y <= z and (x != z or y == x)] from sage.combinat.posets.posets import Poset return Poset((pl, comp2)) def from_antichain(self, acl) -> PP: r""" - Return the cyclically symmetric plane partition corresponding to an + Return the cyclically symmetric plane partition corresponding to an antichain in the poset given in :meth:`to_poset()`. EXAMPLES:: @@ -2068,45 +2065,46 @@ def from_antichain(self, acl) -> PP: """ b = self._box[1] c = self._box[2] - ppMatrix = [[0] * (c) for i in range(b)] - #creates a matrix for the plane partition populated by 0s - #EX: [[0,0,0], [0,0,0], [0,0,0]] - #ac format ex: [x,y,z] + pp_matrix = [[0] * (c) for i in range(b)] + # creates a matrix for the plane partition populated by 0s + # EX: [[0,0,0], [0,0,0], [0,0,0]] + # ac format ex: [x,y,z] for ac in acl: x = ac[0] y = ac[1] z = ac[2] - ppMatrix[y][z] = (x+1) - ppMatrix[z][x] = (y+1) - ppMatrix[x][y] = (z+1) + pp_matrix[y][z] = (x+1) + pp_matrix[z][x] = (y+1) + pp_matrix[x][y] = (z+1) - #for each value in current antichain, fill in the rest of the - #matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is - #now in plane partition format + # For each value in current antichain, fill in the rest of the + # matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is + # now in plane partition format. if acl != []: for i in range(b): i = b - (i + 1) for j in range(c): j = c - (j + 1) - if ppMatrix[i][j] == 0: + if pp_matrix[i][j] == 0: iValue = 0 jValue = 0 if i < b - 1: - iValue = ppMatrix[i+1][j] + iValue = pp_matrix[i+1][j] if j < c - 1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue, jValue) - return self.element_class(self, ppMatrix) + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + return self.element_class(self, pp_matrix) def from_order_ideal(self, I) -> PP: r""" - Return the cylically symmetric plane partition corresponding + Return the cylically symmetric plane partition corresponding to an order ideal in the poset given in :meth:`to_poset`. EXAMPLES:: sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') - sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), (1, 0, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2)] + sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), + ....: (1, 0, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2)] sage: PP.from_order_ideal(I) Plane partition [[3, 3, 3], [3, 3, 3], [3, 3, 2]] """ @@ -2120,7 +2118,7 @@ def random_element(self) -> PP: This uses the :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` - method and the natural bijection between cyclically symmetric plane + method and the natural bijection between cyclically symmetric plane partitions and order ideals in an associated poset. EXAMPLES:: @@ -2130,7 +2128,7 @@ def random_element(self) -> PP: Plane partition [[3, 2, 2], [3, 1], [1, 1]] """ Z = self.from_order_ideal(self.to_poset().random_order_ideal()) - return self.element_class(self, Z, check=False) + return self.element_class(self, Z, check=False) def __iter__(self) -> Iterator: """ @@ -2152,13 +2150,13 @@ def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of cyclically symmetric plane partitions inside an + The number of cyclically symmetric plane partitions inside an `a \times a \times a` box is equal to .. MATH:: - \left(\prod_{i=1}^{a} \frac{3i - 1}{3i - 2}\right) - \left(\prod_{1 \leq i < j \leq a} \frac{i+j+a-1}{2i+j-1}\right) + \left(\prod_{i=1}^{a} \frac{3i - 1}{3i - 2}\right) + \left(\prod_{1 \leq i < j \leq a} \frac{i+j+a-1}{2i+j-1}\right). EXAMPLES:: @@ -2167,15 +2165,14 @@ 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) + 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) + # Class 4 # Totally Symmetric Plane Partitions @@ -2186,6 +2183,8 @@ class PlanePartitions_TSPP(PlanePartitions): """ def __init__(self, box_size): """ + Initialize ``self``. + TESTS:: sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') @@ -2223,7 +2222,7 @@ def __contains__(self, x) -> bool: P = PlanePartition(x) maxval = (P._max_x, P._max_y, P._max_z) return (PlanePartitions.__contains__(self, x) and P.is_TSPP() - and all(a <= b for a,b in zip(maxval, self._box))) + and all(a <= b for a, b in zip(maxval, self._box))) def to_poset(self): r""" @@ -2242,17 +2241,17 @@ def to_poset(self): b = self._box[1] c = self._box[2] - def comp(x,y): + def comp(x, y): return all(a <= b for a, b in zip(x, y)) - pl = [(x,y,z) for x in range(a) for y in range(x, b) for z in range(y, c)] + pl = [(x, y, z) for x in range(a) for y in range(x, b) for z in range(y, c)] from sage.combinat.posets.posets import Poset - return Poset((pl,comp)) + return Poset((pl, comp)) def from_antichain(self, acl) -> PP: r""" - Return the totally symmetric plane partition corresponding to an antichain - in the poset given in :meth:`to_poset()`. + Return the totally symmetric plane partition corresponding to an + antichain in the poset given in :meth:`to_poset()`. EXAMPLES:: @@ -2263,41 +2262,41 @@ def from_antichain(self, acl) -> PP: """ b = self._box[1] c = self._box[2] - ppMatrix = [[0] * (c) for i in range(b)] #creates a matrix for the plane - #partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + pp_matrix = [[0] * (c) for i in range(b)] # creates a matrix for the plane + # partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] for ac in acl: x = ac[0] y = ac[1] z = ac[2] - ppMatrix[y][z] = x + 1 #x,y,z - ppMatrix[z][x] = y + 1 #y,z,x - ppMatrix[x][y] = z + 1 #z,x,y + pp_matrix[y][z] = x + 1 # x,y,z + pp_matrix[z][x] = y + 1 # y,z,x + pp_matrix[x][y] = z + 1 # z,x,y - ppMatrix[z][y] = x + 1 #x,z,y - ppMatrix[x][z] = y + 1 #y,x,z - ppMatrix[y][x] = z + 1 #z,y,x + pp_matrix[z][y] = x + 1 # x,z,y + pp_matrix[x][z] = y + 1 # y,x,z + pp_matrix[y][x] = z + 1 # z,y,x - #for each value in current antichain, fill in the rest of the matrix by - #rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format + # for each value in current antichain, fill in the rest of the matrix by + # rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format if acl != []: for i in range(b): i = b - (i + 1) for j in range(c): j = c - (j + 1) - if ppMatrix[i][j] == 0: + if pp_matrix[i][j] == 0: iValue = 0 jValue = 0 if i < b - 1: - iValue = ppMatrix[i+1][j] + iValue = pp_matrix[i+1][j] if j < c - 1: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue, jValue) - return self.element_class(self, ppMatrix) + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + return self.element_class(self, pp_matrix) def from_order_ideal(self, I) -> PP: r""" - Return the totally symmetric plane partition corresponding + Return the totally symmetric plane partition corresponding to an order ideal in the poset given in :meth:`to_poset`. EXAMPLES:: @@ -2307,7 +2306,7 @@ def from_order_ideal(self, I) -> PP: sage: PP.from_order_ideal(I) Plane partition [[3, 2, 1], [2, 1], [1]] """ - return self.from_antichain(self.to_poset().order_ideal_generators(I)) + return self.from_antichain(self.to_poset().order_ideal_generators(I)) def __iter__(self) -> Iterator: """ @@ -2329,12 +2328,12 @@ def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of totally symmetric plane partitions inside an + The number of totally symmetric plane partitions inside an `a \times a \times a` box is equal to .. MATH:: - \prod_{1 \leq i \leq j \leq a} \frac{i+j+a-1}{i+2j-2} + \prod_{1 \leq i \leq j \leq a} \frac{i+j+a-1}{i+2j-2}. EXAMPLES:: @@ -2343,7 +2342,9 @@ 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) / (i + 2*j - 2) + for j in range(1, a+1) for i in range(1, j+1))) + # Class 5 # Self-complementary Plane Partitions @@ -2354,6 +2355,8 @@ class PlanePartitions_SCPP(PlanePartitions): """ def __init__(self, box_size): """ + Initialize ``self``. + TESTS:: sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') @@ -2364,7 +2367,7 @@ def __init__(self, box_size): ValueError: dimensions (5,3,1) cannot all be odd """ if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): - raise ValueError("dimensions ({},{},{}) cannot all be odd".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("dimensions ({},{},{}) cannot all be odd".format(*box_size)) super().__init__(box_size, "SCPP", category=FiniteEnumeratedSets()) def __contains__(self, x) -> bool: @@ -2380,9 +2383,9 @@ def __contains__(self, x) -> bool: sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='SCPP') False """ - #P = PlanePartitions(self._box)(x) - #max = (P._max_x, P._max_y, P._max_z) - #return PlanePartitions.__contains__(self, x) and P.is_SCPP() and all( a<=b for a,b in zip(max,self._box)) + # P = PlanePartitions(self._box)(x) + # max = (P._max_x, P._max_y, P._max_z) + # return PlanePartitions.__contains__(self, x) and P.is_SCPP() and all( a<=b for a,b in zip(max,self._box)) return x in PlanePartitions(self._box) and PlanePartitions(self._box)(x).is_SCPP() def _repr_(self) -> str: @@ -2414,55 +2417,54 @@ def __iter__(self) -> Iterator: c = self._box[2] def Partitions_inside_lambda(la): - "Return the list of partitions contained in la with the same number of parts including 0s." + "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_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 - def Partitions_inside_lambda_with_smallest_at_least_k(la,k): - "Return the list of partitions contained in la with the smallest entry at least k" + 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]): yield [mu[i] + k for i in range(len(la))] return - def possible_middle_row_for_b_odd(a,c): - "Return the list of possible middle row for SCPP inside box(a,b,c) when b is odd" + 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." if a * c % 2 == 1: yield return - for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor(a/2))]): - nu = [c-mu[len(mu)-1-i] for i in range(len(mu))] - if a % 2 == 0: + for mu in Partitions_inside_lambda([c // 2 for i in range(a // 2)]): + nu = [c - mu[len(mu)-1-i] for i in range(len(mu))] + 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): - "Return the list of possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even" - for mu in Partitions_inside_lambda([floor(c/2) for i in range(floor((a+1)/2))]): - nu = [c - mu[len(mu)-1-i] for i in range(floor(a/2))] - for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu,mu[0]): + 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." + for mu in Partitions_inside_lambda([c // 2 for i in range((a+1) // 2)]): + 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) + yield la return - def PPs_with_first_row_la_and_with_k_rows(la,k): - "Return PPs with first row la and with k rows in total" + 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." if k == 0: yield [] return @@ -2471,26 +2473,26 @@ def PPs_with_first_row_la_and_with_k_rows(la,k): return 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) + yield [la] + PP return - def complement(PP,c): + def complement(PP, c): "Return the complement of PP with respect to height c" - if len(PP) == 0: - return [] b = len(PP) + if not b: + return [] a = len(PP[0]) - return [[c-PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] + 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 - for PP in PPs_with_first_row_la_and_with_k_rows(la, (b+1)//2): + 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 - for PP in PPs_with_first_row_la_and_with_k_rows(la, b//2): + for la in possible_middle_row_for_b_even(a, c): # la is the middle ((a/2)+1)st row of SCPP + 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) @@ -2500,28 +2502,29 @@ def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of self complementary plane partitions inside a + The number of self complementary plane partitions inside a `2a \times 2b \times 2c` box is equal to .. MATH:: - \left(\prod_{i=1}^{r}\prod_{j=1}^{b} \frac{i + j + c - 1}{i + j - 1}\right)^2. + \left(\prod_{i=1}^{r}\prod_{j=1}^{b} + \frac{i + j + c - 1}{i + j - 1}\right)^2. - The number of self complementary plane partitions inside an + The number of self complementary plane partitions inside an `(2a+1) \times 2b \times 2c` box is equal to .. MATH:: - \left(\prod_{i=1}^{a}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right). + \left(\prod_{i=1}^{a} \prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a+1} \prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right). - The number of self complementary plane partitions inside an + The number of self complementary plane partitions inside an `(2a+1) \times (2b+1) \times 2c` box is equal to .. MATH:: - \left(\prod_{i=1}^{a+1}\prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) - \left(\prod_{i=1}^{a}\prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right). + \left(\prod_{i=1}^{a+1} \prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a} \prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right). EXAMPLES:: @@ -2559,29 +2562,29 @@ def cardinality(self) -> Integer: if t % 2 == 0: T = t // 2 return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1))) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1))) else: T = (t-1) // 2 return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+2))) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) else: S = (s-1) // 2 if t % 2 == 0: T = t // 2 return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+2) for k in range(1,T+1))) + for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1))) else: T = (t-1) // 2 return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+2) for k in range(1,T+1)) + for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1)) * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+2))) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) # r is odd R = (r-1) // 2 if s % 2 == 0: @@ -2589,27 +2592,28 @@ def cardinality(self) -> Integer: if t % 2 == 0: T = t // 2 return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+1)) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+2) for j in range(1,S+1) for k in range(1,T+1))) + for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1))) else: T = (t-1) // 2 return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+2) for j in range(1,S+1) for k in range(1,T+1)) + for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1)) * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+1) for k in range(1,T+2))) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) # r and s are both odd S = (s-1) // 2 if t % 2 == 0: T = t // 2 return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+2) for j in range(1,S+1) for k in range(1,T+1)) + for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1)) * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1,R+1) for j in range(1,S+2) for k in range(1,T+1))) + for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1))) # Should never reach here as r, s, t are all odd, which the constructor should reject return Integer(0) + # Class 6 # Transpose-complement Plane Partitions class PlanePartitions_TCPP(PlanePartitions): @@ -2619,8 +2623,10 @@ class PlanePartitions_TCPP(PlanePartitions): """ def __init__(self, box_size): """ + Initialize ``self``. + TESTS:: - + sage: PP = PlanePartitions([3,3,2], symmetry='TCPP') sage: TestSuite(PP).run() @@ -2634,10 +2640,10 @@ def __init__(self, box_size): ... ValueError: x and y dimensions (4 and 3) must be equal """ - if (box_size[2] % 2 == 1): + if box_size[2] % 2 == 1: raise ValueError("z dimension ({}) must be even".format(box_size[2])) if box_size[0] != box_size[1]: - raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0],box_size[1])) + raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) super().__init__(box_size, "TCPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: @@ -2665,19 +2671,20 @@ def __iter__(self) -> Iterator: """ for p in PlanePartitions(self._box): if p.is_TCPP(): - yield self.element_class(self,p) + yield self.element_class(self, p) return def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of transpose complement plane partitions inside an + The number of transpose complement plane partitions inside an `a \times a \times 2b` box is equal to .. MATH:: - \binom{b+1-1}{a-1}\prod_{1\leq i,j \leq a-2} \frac{i + j + 2b - 1}{i + j - 1} + \binom{b+1-1}{a-1} \prod_{1\leq i,j \leq a-2} + \frac{i + j + 2b - 1}{i + j - 1}. EXAMPLES:: @@ -2687,7 +2694,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,1+a-2) for i in range(1,1+j))) + 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))) + # Class 7 # Symmetric Self-complementary Plane Partitions @@ -2698,20 +2708,22 @@ class PlanePartitions_SSCPP(PlanePartitions): """ def __init__(self, box_size): """ + Initialize ``self``. + TESTS:: - sage: PP = PlanePartitions([2,2,4], symmetry='SSCPP') + sage: PP = PlanePartitions([2, 2, 4], symmetry='SSCPP') sage: TestSuite(PP).run() - sage: PP = PlanePartitions([4,4,2], symmetry='SSCPP') + sage: PP = PlanePartitions([4, 4, 2], symmetry='SSCPP') sage: TestSuite(PP).run() # long time - sage: PlanePartitions([4,2,2], symmetry='SSCPP') + sage: PlanePartitions([4, 2, 2], symmetry='SSCPP') Traceback (most recent call last): ... ValueError: x and y dimensions (4 and 2) must be equal - sage: PlanePartitions([4,4,3], symmetry='SSCPP') + sage: PlanePartitions([4, 4, 3], symmetry='SSCPP') Traceback (most recent call last): ... ValueError: z dimension (3) must be even @@ -2726,7 +2738,7 @@ def _repr_(self) -> str: """ EXAMPLES:: - sage: PlanePartitions([4,4,2], symmetry='SSCPP') + sage: PlanePartitions([4, 4, 2], symmetry='SSCPP') Symmetric self-complementary plane partitions inside a 4 x 4 x 2 box """ return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( @@ -2748,25 +2760,25 @@ def __iter__(self) -> Iterator: """ for p in PlanePartitions(self._box): if p.is_SSCPP(): - yield self.element_class(self,p) + yield self.element_class(self, p) def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of symmetric self-complementary plane partitions inside a + The number of symmetric self-complementary plane partitions inside a `2a \times 2a \times 2b` box is equal to .. MATH:: - \prod_{i=1}^{a}\prod_{j=1}^{a} \frac{i + j + b - 1}{i + j - 1}. + \prod_{i=1}^a \prod_{j=1}^a \frac{i + j + b - 1}{i + j - 1}. - The number of symmetric self-complementary plane partitions inside a + The number of symmetric self-complementary plane partitions inside a `(2a+1) \times (2a+1) \times 2b` box is equal to .. MATH:: - \prod_{i=1}^{a}\prod_{j=1}^{a+1} \frac{i + j + b - 1}{i + j - 1}. + \prod_{i=1}^a \prod_{j=1}^{a+1} \frac{i + j + b - 1}{i + j - 1}. EXAMPLES:: @@ -2779,13 +2791,14 @@ 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+floor(a/2)) - for j in range(1,1+ceil(a/2)) - for k in range(1,1+c/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))) + # Class 8 -#Cyclically Symmetric Transpose-complement Partitions +# Cyclically Symmetric Transpose-complement Partitions class PlanePartitions_CSTCPP(PlanePartitions): r""" Plane partitions that fit inside a box of a specified size that are @@ -2809,9 +2822,9 @@ def __init__(self, box_size): ValueError: x, y, and z dimensions (3,3,3) must all be even """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) if box_size[0] % 2 == 1: - raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(*box_size)) super().__init__(box_size, "CSTPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: @@ -2835,18 +2848,18 @@ def __iter__(self) -> Iterator: """ for p in PlanePartitions(self._box): if p.is_CSTCPP(): - yield self.element_class(self,p) + yield self.element_class(self, p) def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of cyclically symmetric transpose complement plane partitions + The number of cyclically symmetric transpose complement plane partitions inside a `2a \times 2a \times 2a` box is equal to .. MATH:: - \prod_{i=0}^{a-1} \frac{(3i+1)(6i)!(2i)!}{(4i+1)!(4i)!} + \prod_{i=0}^{a-1} \frac{(3i+1)(6i)!(2i)!}{(4i+1)!(4i)!}. EXAMPLES:: @@ -2857,6 +2870,7 @@ def cardinality(self) -> Integer: 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))) + # Class 9 # Cyclically Symmetric Self-complementary Plane Partitions class PlanePartitions_CSSCPP(PlanePartitions): @@ -2865,9 +2879,11 @@ class PlanePartitions_CSSCPP(PlanePartitions): cyclically symmetric self-complementary. """ def __init__(self, box_size): - """ + r""" + Initialize ``self``. + TESTS:: - + sage: PP = PlanePartitions([2,2,2], symmetry='CSSCPP') sage: TestSuite(PP).run() sage: PlanePartitions([4,3,2], symmetry='CSSCPP') @@ -2880,9 +2896,9 @@ def __init__(self, box_size): ValueError: x, y, and z dimensions (3,3,3) must all be even """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) if box_size[0] % 2 == 1: - raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(*box_size)) super().__init__(box_size, "CSSCPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: @@ -2906,18 +2922,18 @@ def __iter__(self) -> Iterator: """ for p in PlanePartitions(self._box): if p.is_CSSCPP(): - yield self.element_class(self,p) + yield self.element_class(self, p) def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of cyclically symmetric self-complementary plane partitions + The number of cyclically symmetric self-complementary plane partitions inside a `2a \times 2a \times 2a` box is equal to .. MATH:: - \left(\prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}\right)^2 + \left( \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!} \right)^2. EXAMPLES:: @@ -2928,6 +2944,7 @@ def cardinality(self) -> Integer: a = self._box[0] // 2 return Integer(prod(factorial(3*i+1)**2 / factorial(a+i)**2 for i in range(a))) + # Class 10 # Totally Symmetric Self-complementary Plane Partitions class PlanePartitions_TSSCPP(PlanePartitions): @@ -2951,9 +2968,9 @@ def __init__(self, box_size): ValueError: x, y, and z dimensions (3,3,3) must all be even """ if box_size[0] != box_size[1] or box_size[1] != box_size[2]: - raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) if box_size[0] % 2 == 1: - raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(box_size[0],box_size[1],box_size[2])) + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(*box_size)) super().__init__(box_size, "TSSCPP", category=FiniteEnumeratedSets()) def _repr_(self) -> str: @@ -2990,13 +3007,13 @@ def comp(x, y): return all(xx <= yy for xx, yy in zip(x, y)) A = a // 2 - pl = [(x,y,z) for x in range(A-1) for y in range(x, A-1) + pl = [(x, y, z) for x in range(A-1) for y in range(x, A-1) for z in range(A-1) if z <= A - 2 - y] return Poset((pl, comp)) - + def from_antichain(self, acl) -> PP: r""" - Return the totally symmetric self-complementary plane partition + Return the totally symmetric self-complementary plane partition corresponding to an antichain in the poset given in :meth:`to_poset()`. EXAMPLES:: @@ -3006,15 +3023,15 @@ def from_antichain(self, acl) -> PP: sage: PP.from_antichain(A) Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 4, 3, 1], [6, 5, 4, 3, 2, 1], [5, 4, 3, 2, 1], [5, 3, 2, 1, 1], [3, 1, 1]] """ - #ac format ex: [x,y,z] + # ac format ex: [x,y,z] a = self._box[0] b = self._box[1] c = self._box[2] n = a N = n // 2 - ppMatrix = [[0] * (c) for i in range(b)] - #creates a matrix for the plane parition populated by 0s - #EX: [[0,0,0], [0,0,0], [0,0,0]] + pp_matrix = [[0] * (c) for i in range(b)] + # creates a matrix for the plane parition populated by 0s + # EX: [[0,0,0], [0,0,0], [0,0,0]] width = N - 1 height = N - 1 @@ -3025,9 +3042,9 @@ def from_antichain(self, acl) -> PP: for ac in acl: if ac[0] == i and ac[1] == j: zVal = ac[2] - matrixVal = ppMatrix[j+N][i+N] + matrixVal = pp_matrix[j+N][i+N] if zVal + 1 > matrixVal: - ppMatrix[j+N][i+N] = zVal + 1 + pp_matrix[j+N][i+N] = zVal + 1 # fill back for i in range(width): @@ -3036,62 +3053,62 @@ def from_antichain(self, acl) -> PP: for j in range(height): j = height - (j + 1) j = j + N - if ppMatrix[i][j] == 0: + if pp_matrix[i][j] == 0: if i >= j: iValue = 0 jValue = 0 if i < n: - iValue = ppMatrix[i+1][j] + iValue = pp_matrix[i+1][j] if j < n: - jValue = ppMatrix[i][j+1] - ppMatrix[i][j] = max(iValue,jValue) + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) - #fill half of triangle symmetrically + # fill half of triangle symmetrically for i in range(width): i += N for j in range(height): j += N if i >= j: - ppMatrix[j][i] = ppMatrix[i][j] + pp_matrix[j][i] = pp_matrix[i][j] - #upper left box + # upper left box for i in range(N): for j in range(N): - ppMatrix[i][j] = n - ppMatrix[n-(i+1)][n-(j+1)] + pp_matrix[i][j] = n - pp_matrix[n-(i+1)][n-(j+1)] - #fill in lower left cube with values n/2 + # fill in lower left cube with values n/2 for i in range(N): for j in range(N): x = i y = j - if ppMatrix[x][y+N] == 0: - ppMatrix[x][y+N] = N - if ppMatrix[x+N][y] == 0: - ppMatrix[x+N][y] = N + if pp_matrix[x][y+N] == 0: + pp_matrix[x][y+N] = N + if pp_matrix[x+N][y] == 0: + pp_matrix[x+N][y] = N - #add and subtract values from lower left cube to be rotation of lower right cube + # add and subtract values from lower left cube to be rotation of lower right cube for i in range(N): for j in range(N): x = i + N y = j + N - if ppMatrix[x][y] > 0: - z = ppMatrix[x][y] + if pp_matrix[x][y] > 0: + z = pp_matrix[x][y] for cVal in range(z): - #build onto lower left cube - ppMatrix[x][0+cVal] += 1 - #carve out of lower left cube - ppMatrix[n-(1+cVal)][N-(j+1)] -= 1 + # build onto lower left cube + pp_matrix[x][0+cVal] += 1 + # carve out of lower left cube + pp_matrix[n-(1+cVal)][N-(j+1)] -= 1 - #fill in upper right cube symmetrically with lower left + # fill in upper right cube symmetrically with lower left for i in range(N): for j in range(N): - ppMatrix[j][i+N] = ppMatrix[i+N][j] - return self.element_class(self, ppMatrix) + pp_matrix[j][i+N] = pp_matrix[i+N][j] + return self.element_class(self, pp_matrix) def from_order_ideal(self, I) -> PP: r""" - Return the totally symmetric self-complementary plane partition corresponding - to an order ideal in the poset given in :meth:`to_poset`. + Return the totally symmetric self-complementary plane partition + corresponding to an order ideal in the poset given in :meth:`to_poset`. EXAMPLES:: @@ -3120,7 +3137,7 @@ def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - The number of totally symmetric self-complementary plane partitions + The number of totally symmetric self-complementary plane partitions inside a `2a \times 2a \times 2a` box is equal to .. MATH:: @@ -3135,4 +3152,3 @@ def cardinality(self) -> Integer: """ a = self._box[0] // 2 return Integer(prod(factorial(3*i+1) / factorial(a+i) for i in range(a))) - From 9ff10da878fd375253689b3fa71ca169a55a849b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 15 Feb 2023 12:05:07 +0900 Subject: [PATCH 73/74] Fixing issue with NewType. --- src/sage/combinat/plane_partition.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 811b9365400..08e22ee1f7d 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -44,8 +44,6 @@ from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers -PP = NewType('PP', 'PlanePartition') - @richcmp_method class PlanePartition(ClonableArray, @@ -1170,6 +1168,9 @@ def bounding_box(self): return (len(self), len(self[0]), self[0][0]) +PP = NewType('PP', PlanePartition) + + class PlanePartitions(UniqueRepresentation, Parent): r""" Plane partitions. From 22b04b85ec8cf774562d670f55018a0561b585a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Mar 2023 10:06:03 +0200 Subject: [PATCH 74/74] Update plane_partition.py change the import of ZZ --- src/sage/combinat/plane_partition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 08e22ee1f7d..642bcca5ed0 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -37,7 +37,7 @@ from sage.structure.list_clone import ClonableArray from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.misc import Sigma from sage.functions.other import floor, ceil, binomial, factorial from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets