@@ -5939,7 +5939,7 @@ class Partitions(UniqueRepresentation, Parent):
5939
5939
and ``length``::
5940
5940
5941
5941
sage: Partitions(5, min_part=2)
5942
- Partitions of 5 having parts at least 2
5942
+ Partitions of 5 whose parts are at least 2
5943
5943
sage: Partitions(5, min_part=2).list()
5944
5944
[[5], [3, 2]]
5945
5945
@@ -6030,7 +6030,7 @@ class Partitions(UniqueRepresentation, Parent):
6030
6030
sage: TestSuite(Partitions(5, min_part=2)).run() # needs sage.libs.flint
6031
6031
6032
6032
sage: repr(Partitions(5, min_part=2))
6033
- 'Partitions of 5 having parts at least 2'
6033
+ 'Partitions of 5 whose parts are at least 2'
6034
6034
6035
6035
sage: P = Partitions(5, min_part=2)
6036
6036
sage: P.first().parent()
@@ -6173,7 +6173,7 @@ def __classcall_private__(cls, n=None, **kwargs):
6173
6173
if 'max_part' in kwargs :
6174
6174
return PartitionsGreatestLE (n , kwargs ['max_part' ])
6175
6175
if 'min_part' in kwargs :
6176
- return PartitionsSmallestGE (n , kwargs ['min_part' ], 0 , n )
6176
+ return Partitions_parts_length_restricted (n , kwargs ['min_part' ], n , 0 , n )
6177
6177
if 'length' in kwargs :
6178
6178
return Partitions_nk (n , kwargs ['length' ])
6179
6179
@@ -6201,15 +6201,17 @@ def __classcall_private__(cls, n=None, **kwargs):
6201
6201
if 'length' in kwargs and ('min_length' in kwargs or 'max_length' in kwargs ):
6202
6202
raise ValueError ("do not specify the length together with the minimal or maximal length" )
6203
6203
6204
- if set (kwargs ).issubset (['length' , 'min_part' ,
6204
+ if set (kwargs ).issubset (['length' , 'min_part' , 'max_part' ,
6205
6205
'min_length' , 'max_length' ]):
6206
6206
if 'length' in kwargs :
6207
- return PartitionsSmallestGE (n , kwargs .get ('min_part' , 1 ),
6208
- kwargs ['length' ],
6209
- kwargs ['length' ])
6210
- return PartitionsSmallestGE (n , kwargs .get ('min_part' , 1 ),
6211
- kwargs .get ('min_length' , 0 ),
6212
- kwargs .get ('max_length' , n ))
6207
+ return Partitions_parts_length_restricted (n , kwargs .get ('min_part' , 1 ),
6208
+ kwargs .get ('max_part' , n ),
6209
+ kwargs ['length' ],
6210
+ kwargs ['length' ])
6211
+ return Partitions_parts_length_restricted (n , kwargs .get ('min_part' , 1 ),
6212
+ kwargs .get ('max_part' , n ),
6213
+ kwargs .get ('min_length' , 0 ),
6214
+ kwargs .get ('max_length' , n ))
6213
6215
6214
6216
# FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute
6215
6217
kwargs ['name' ] = "Partitions of the integer {} satisfying constraints {}" .format (n , ", " .join (["{}={}" .format (key , kwargs [key ]) for key in sorted (kwargs )]))
@@ -7445,7 +7447,7 @@ def subset(self, **kwargs):
7445
7447
sage: P = Partitions(5, length=2); P
7446
7448
Partitions of the integer 5 of length 2
7447
7449
sage: P.subset(max_part=3)
7448
- Partitions of the integer 5 satisfying constraints length=2, max_part= 3
7450
+ Partitions of 5 having length 2 and whose parts are at most 3
7449
7451
"""
7450
7452
return Partitions (self .n , length = self .k , ** kwargs )
7451
7453
@@ -8831,110 +8833,176 @@ def cardinality(self):
8831
8833
return ZZ (ans )
8832
8834
8833
8835
8834
- ##########################
8835
- # Partitions Smallest GE #
8836
- ##########################
8836
+ ######################################
8837
+ # Partitions_parts_length_restricted #
8838
+ ######################################
8837
8839
8838
- class PartitionsSmallestGE (UniqueRepresentation , IntegerListsLex ):
8840
+ class Partitions_parts_length_restricted (UniqueRepresentation , IntegerListsLex ):
8839
8841
r"""
8840
- The class of all partitions of the integer `n` having parts
8841
- at least `k` and restricted length.
8842
+ The class of all integer partitions having parts and length in a
8843
+ given range.
8844
+
8845
+ This class is strictly more general than
8846
+ :class:`PartitionsGreatestLE`.
8847
+
8848
+ INPUT:
8849
+
8850
+ - ``n`` -- the size of the partition
8851
+ - ``min_part`` -- the bound on the smallest part
8852
+ - ``max_part`` -- the bound on the largest part
8853
+ - ``min_length`` -- the lower bound on the number of parts
8854
+ - ``max_length`` -- the upper bound on the number of parts
8842
8855
8843
8856
EXAMPLES::
8844
8857
8845
- sage: from sage.combinat.partition import PartitionsSmallestGE
8846
- sage: PartitionsSmallestGE (10, 2, 0, 10)
8847
- Partitions of 10 having parts at least 2
8848
- sage: list(PartitionsSmallestGE (9, 2, 3, 4))
8849
- [[5, 2, 2], [ 4, 3, 2], [3, 3, 3], [3, 2, 2, 2]]
8858
+ sage: from sage.combinat.partition import Partitions_parts_length_restricted
8859
+ sage: Partitions_parts_length_restricted (10, 2, 5 , 0, 10)
8860
+ Partitions of 10 whose parts are between 2 and 5
8861
+ sage: list(Partitions_parts_length_restricted (9, 2, 4 , 3, 4))
8862
+ [[4, 3, 2], [3, 3, 3], [3, 2, 2, 2]]
8850
8863
8851
- sage: [4,3,2,1] in PartitionsSmallestGE (10, 2, 0, 10)
8864
+ sage: [4,3,2,1] in Partitions_parts_length_restricted (10, 2, 10 , 0, 10)
8852
8865
False
8853
- sage: [2,2,2,2,2] in PartitionsSmallestGE (10, 2, 0, 10)
8866
+ sage: [2,2,2,2,2] in Partitions_parts_length_restricted (10, 2, 10 , 0, 10)
8854
8867
True
8855
8868
"""
8856
8869
@staticmethod
8857
- def __classcall_private__ (cls , n , min_part , min_length , max_length ):
8870
+ def __classcall_private__ (cls , n , min_part , max_part , min_length , max_length ):
8858
8871
"""
8859
8872
Normalize the input to ensure a unique representation.
8860
8873
8861
8874
TESTS::
8862
8875
8863
- sage: from sage.combinat.partition import PartitionsSmallestGE
8864
- sage: P1 = PartitionsSmallestGE (9, 0, -1, 10)
8865
- sage: P2 = PartitionsSmallestGE (9, 1, 0, 10 )
8876
+ sage: from sage.combinat.partition import Partitions_parts_length_restricted
8877
+ sage: P1 = Partitions_parts_length_restricted (9, 0, 20 , -1, 10)
8878
+ sage: P2 = Partitions_parts_length_restricted (9, 1, 9, 0, 9 )
8866
8879
sage: P1 is P2
8867
8880
True
8868
8881
"""
8869
8882
n = ZZ (n )
8870
- min_part = max (min_part , ZZ .one ())
8871
- min_length = max (min_length , ZZ .zero ())
8872
- max_length = min (max_length , n )
8873
- return super ().__classcall__ (cls , n , min_part , min_length , max_length )
8874
-
8875
- def __init__ (self , n , min_part , min_length , max_length ):
8883
+ if min_part <= 0 :
8884
+ min_part = ZZ .one ()
8885
+ if max_part > n :
8886
+ max_part = n
8887
+ if max_part < 0 :
8888
+ max_part = ZZ .zero ()
8889
+ if min_length < 0 :
8890
+ min_length = ZZ .zero ()
8891
+ if max_length > n :
8892
+ max_length = n
8893
+ return super ().__classcall__ (cls , n , min_part , max_part , min_length , max_length )
8894
+
8895
+ def __init__ (self , n , min_part , max_part , min_length , max_length ):
8876
8896
"""
8877
8897
Initialize ``self``.
8878
8898
8879
8899
TESTS::
8880
8900
8881
- sage: from sage.combinat.partition import PartitionsSmallestGE
8882
- sage: p = PartitionsSmallestGE (10, 2, 0, 10 )
8901
+ sage: from sage.combinat.partition import Partitions_parts_length_restricted
8902
+ sage: p = Partitions_parts_length_restricted (10, 2, 5, 3, 4 )
8883
8903
sage: TestSuite(p).run()
8884
8904
"""
8885
8905
self ._n = n
8886
- self ._min_part = min_part
8887
- self ._min_length = min_length
8888
- self ._max_length = max_length
8889
8906
8890
8907
IntegerListsLex .__init__ (self , self ._n , max_slope = 0 ,
8891
- min_part = self ._min_part ,
8892
- min_length = self ._min_length ,
8893
- max_length = self ._max_length )
8908
+ min_part = min_part ,
8909
+ max_part = max_part ,
8910
+ min_length = min_length ,
8911
+ max_length = max_length )
8912
+
8913
+ self ._min_part = ZZ .one () if min_part is None else min_part
8914
+ self ._max_part = self ._n if max_part is None else max_part
8915
+ self ._min_length = ZZ .zero () if min_length is None else min_length
8916
+ self ._max_length = self ._n if max_length is None else max_length
8894
8917
8895
8918
def _repr_ (self ):
8896
8919
"""
8897
8920
Return a string representation of ``self``.
8898
8921
8899
8922
TESTS::
8900
8923
8901
- sage: from sage.combinat.partition import PartitionsSmallestGE
8902
- sage: PartitionsSmallestGE(9, 2, 0, 10)
8903
- Partitions of 9 having parts at least 2
8904
- sage: PartitionsSmallestGE(9, 2, 3, 5)
8905
- Partitions of 9 having length between 3 and 5 and parts at least 2
8906
- """
8907
- if self ._min_length == self ._max_length :
8908
- return f"Partitions of { self ._n } having length { self ._min_length } and parts at least { self ._min_part } "
8909
- if not self ._min_length or (self ._n and self ._min_length == 1 ):
8910
- if self ._max_length >= self ._n :
8911
- return f"Partitions of { self ._n } having parts at least { self ._min_part } "
8912
- return f"Partitions of { self ._n } having length at most { self ._max_length } and parts at least { self ._min_part } "
8913
- if self ._max_length >= self ._n :
8914
- return f"Partitions of { self ._n } having length at least { self ._min_length } and parts at least { self ._min_part } "
8915
- return f"Partitions of { self ._n } having length between { self ._min_length } and { self ._max_length } and parts at least { self ._min_part } "
8924
+ sage: from sage.combinat.partition import Partitions_parts_length_restricted
8925
+ sage: Partitions_parts_length_restricted(9, 2, 9, 0, 10)
8926
+ Partitions of 9 whose parts are at least 2
8927
+ sage: Partitions_parts_length_restricted(9, 2, 9, 3, 5)
8928
+ Partitions of 9 having length between 3 and 5 and whose parts are at least 2
8929
+ """
8930
+ if not self ._min_length and self ._max_length == self ._n :
8931
+ length_str = ""
8932
+ elif self ._min_length == self ._max_length :
8933
+ length_str = f"having length { self ._min_length } "
8934
+ elif not self ._min_length :
8935
+ length_str = f"having length at most { self ._max_length } "
8936
+ elif self ._max_length == self ._n :
8937
+ length_str = f"having length at least { self ._min_length } "
8938
+ else :
8939
+ length_str = f"having length between { self ._min_length } and { self ._max_length } "
8940
+
8941
+ if self ._min_part == ZZ .one () and self ._max_part == self ._n :
8942
+ parts_str = ""
8943
+ elif self ._min_part == self ._max_part :
8944
+ parts_str = f"having parts equal to { self ._min_part } "
8945
+ elif self ._min_part == ZZ .one ():
8946
+ parts_str = f"whose parts are at most { self ._max_part } "
8947
+ elif self ._max_part == self ._n :
8948
+ parts_str = f"whose parts are at least { self ._min_part } "
8949
+ else :
8950
+ parts_str = f"whose parts are between { self ._min_part } and { self ._max_part } "
8951
+
8952
+ if length_str :
8953
+ if parts_str :
8954
+ return f"Partitions of { self ._n } " + length_str + " and " + parts_str
8955
+ return f"Partitions of { self ._n } " + length_str
8956
+ if parts_str :
8957
+ return f"Partitions of { self ._n } " + parts_str
8958
+ return f"Partitions of { self ._n } "
8916
8959
8917
8960
def cardinality (self ):
8918
8961
"""
8919
8962
Return the cardinality of ``self``.
8920
8963
8921
8964
EXAMPLES::
8922
8965
8923
- sage: from sage.combinat.partition import PartitionsSmallestGE
8924
- sage: list(PartitionsSmallestGE (9, 3, 0, 2))
8966
+ sage: from sage.combinat.partition import Partitions_parts_length_restricted
8967
+ sage: list(Partitions_parts_length_restricted (9, 3, 9 , 0, 2))
8925
8968
[[9], [6, 3], [5, 4]]
8926
- sage: PartitionsSmallestGE (9, 3, 0, 2).cardinality()
8969
+ sage: Partitions_parts_length_restricted (9, 3, 9 , 0, 2).cardinality()
8927
8970
3
8928
8971
8929
8972
TESTS::
8930
8973
8931
- sage: all(PartitionsSmallestGE(n, a, b, c).cardinality() ==
8932
- ....: len(list(PartitionsSmallestGE(n, a, b, c)))
8933
- ....: for n in range(6) for a in range(1, 6) for b in range(6) for c in range(6))
8934
- True
8935
- """
8936
- return sum (number_of_partitions_length (self ._n - (self ._min_part - 1 )* ell , ell )
8937
- for ell in range (self ._min_length , self ._max_length + 1 ))
8974
+ sage: from itertools import product
8975
+ sage: P = Partitions_parts_length_restricted
8976
+ sage: all(P(n, a, b, k, m).cardinality() == len(list(P(n, a, b, k, m)))
8977
+ ....: for n, a, b, k, m in product(range(-1, 5), repeat=5))
8978
+ True
8979
+ """
8980
+ if not self ._min_length and self ._max_length == self ._n and self ._min_part == 1 :
8981
+ # unrestricted length, parts smaller max_part
8982
+ return ZZ .sum (number_of_partitions_length (self ._n , i )
8983
+ for i in range (self ._max_part + 1 ))
8984
+
8985
+ def partitions_len_max_part (n , b , l ):
8986
+ r"""
8987
+ Return the number of partitions of `n` with exactly `l` parts and
8988
+ the largest part at most `b`.
8989
+ """
8990
+ if not n :
8991
+ if not l :
8992
+ return ZZ .one ()
8993
+ return ZZ .zero ()
8994
+ if not l or l > n or n > b * l :
8995
+ return ZZ .zero ()
8996
+ if b >= n :
8997
+ return number_of_partitions_length (n , l )
8998
+
8999
+ return ZZ .sum (partitions_len_max_part (n - m , m , l - 1 )
9000
+ for m in range (1 , b + 1 ))
9001
+
9002
+ return ZZ .sum (partitions_len_max_part (self ._n - (self ._min_part - 1 )* ell ,
9003
+ self ._max_part - self ._min_part + 1 ,
9004
+ ell )
9005
+ for ell in range (self ._min_length , self ._max_length + 1 ))
8938
9006
8939
9007
Element = Partition
8940
9008
options = Partitions .options
0 commit comments