48
48
from sage .rings .integer import Integer
49
49
50
50
51
- def is_gale_ryser (r ,s ):
51
+ def is_gale_ryser (r , s ):
52
52
r"""
53
53
Tests whether the given sequences satisfy the condition
54
54
of the Gale-Ryser theorem.
@@ -314,20 +314,20 @@ def gale_ryser_theorem(p1, p2, algorithm="gale",
314
314
"""
315
315
from sage .matrix .constructor import matrix
316
316
317
- if not is_gale_ryser (p1 ,p2 ):
317
+ if not is_gale_ryser (p1 , p2 ):
318
318
return False
319
319
320
- if algorithm == "ryser" : # ryser's algorithm
320
+ if algorithm == "ryser" : # ryser's algorithm
321
321
from sage .combinat .permutation import Permutation
322
322
323
323
# Sorts the sequences if they are not, and remembers the permutation
324
324
# applied
325
- tmp = sorted (enumerate (p1 ), reverse = True , key = lambda x :x [1 ])
325
+ tmp = sorted (enumerate (p1 ), reverse = True , key = lambda x : x [1 ])
326
326
r = [x [1 ] for x in tmp ]
327
327
r_permutation = [x - 1 for x in Permutation ([x [0 ]+ 1 for x in tmp ]).inverse ()]
328
328
m = len (r )
329
329
330
- tmp = sorted (enumerate (p2 ), reverse = True , key = lambda x :x [1 ])
330
+ tmp = sorted (enumerate (p2 ), reverse = True , key = lambda x : x [1 ])
331
331
s = [x [1 ] for x in tmp ]
332
332
s_permutation = [x - 1 for x in Permutation ([x [0 ]+ 1 for x in tmp ]).inverse ()]
333
333
@@ -340,12 +340,12 @@ def gale_ryser_theorem(p1, p2, algorithm="gale",
340
340
k = i + 1
341
341
while k < m and r [i ] == r [k ]:
342
342
k += 1
343
- if t >= k - i : # == number rows of the same length
343
+ if t >= k - i : # == number rows of the same length
344
344
for j in range (i , k ):
345
345
r [j ] -= 1
346
346
c [j ] = 1
347
347
t -= k - i
348
- else : # Remove the t last rows of that length
348
+ else : # Remove the t last rows of that length
349
349
for j in range (k - t , k ):
350
350
r [j ] -= 1
351
351
c [j ] = 1
@@ -366,17 +366,17 @@ def gale_ryser_theorem(p1, p2, algorithm="gale",
366
366
k1 , k2 = len (p1 ), len (p2 )
367
367
p = MixedIntegerLinearProgram (solver = solver )
368
368
b = p .new_variable (binary = True )
369
- for (i ,c ) in enumerate (p1 ):
370
- p .add_constraint (p .sum ([b [i ,j ] for j in range (k2 )]) == c )
371
- for (i ,c ) in enumerate (p2 ):
372
- p .add_constraint (p .sum ([b [j ,i ] for j in range (k1 )]) == c )
369
+ for (i , c ) in enumerate (p1 ):
370
+ p .add_constraint (p .sum ([b [i , j ] for j in range (k2 )]) == c )
371
+ for (i , c ) in enumerate (p2 ):
372
+ p .add_constraint (p .sum ([b [j , i ] for j in range (k1 )]) == c )
373
373
p .set_objective (None )
374
374
p .solve ()
375
375
b = p .get_values (b , convert = ZZ , tolerance = integrality_tolerance )
376
376
M = [[0 ]* k2 for i in range (k1 )]
377
377
for i in range (k1 ):
378
378
for j in range (k2 ):
379
- M [i ][j ] = b [i ,j ]
379
+ M [i ][j ] = b [i , j ]
380
380
return matrix (M )
381
381
382
382
else :
@@ -780,6 +780,43 @@ def __contains__(self, x):
780
780
return False
781
781
return True
782
782
783
+ def _unrank_helper (self , x , rtn ):
784
+ """
785
+ Return the element at rank ``x`` by iterating through all integer vectors beginning with ``rtn``.
786
+
787
+ INPUT:
788
+
789
+ - ``x`` - a nonnegative integer
790
+ - ``rtn`` - a list of nonnegative integers
791
+
792
+
793
+ EXAMPLES::
794
+
795
+ sage: IV = IntegerVectors(k=5)
796
+ sage: IV._unrank_helper(10, [2,0,0,0,0])
797
+ [1, 0, 0, 0, 1]
798
+
799
+ sage: IV = IntegerVectors(n=7)
800
+ sage: IV._unrank_helper(100, [7,0,0,0])
801
+ [2, 0, 0, 5]
802
+
803
+ sage: IV = IntegerVectors(n=12, k=7)
804
+ sage: IV._unrank_helper(1000, [12,0,0,0,0,0,0])
805
+ [5, 3, 1, 1, 1, 1, 0]
806
+ """
807
+ ptr = 0
808
+ while True :
809
+ current_rank = self .rank (rtn )
810
+ if current_rank < x :
811
+ rtn [ptr + 1 ] = rtn [ptr ]
812
+ rtn [ptr ] = 0
813
+ ptr += 1
814
+ elif current_rank > x :
815
+ rtn [ptr ] -= 1
816
+ rtn [ptr - 1 ] += 1
817
+ else :
818
+ return self ._element_constructor_ (rtn )
819
+
783
820
784
821
class IntegerVectors_all (UniqueRepresentation , IntegerVectors ):
785
822
"""
@@ -839,7 +876,10 @@ def __init__(self, n):
839
876
sage: TestSuite(IV).run()
840
877
"""
841
878
self .n = n
842
- IntegerVectors .__init__ (self , category = InfiniteEnumeratedSets ())
879
+ if self .n == 0 :
880
+ IntegerVectors .__init__ (self , category = EnumeratedSets ())
881
+ else :
882
+ IntegerVectors .__init__ (self , category = InfiniteEnumeratedSets ())
843
883
844
884
def _repr_ (self ):
845
885
"""
@@ -898,6 +938,68 @@ def __contains__(self, x):
898
938
return False
899
939
return sum (x ) == self .n
900
940
941
+ def rank (self , x ):
942
+ """
943
+ Return the rank of a given element.
944
+
945
+ INPUT:
946
+
947
+ - ``x`` -- a list with ``sum(x) == n``
948
+
949
+ EXAMPLES::
950
+
951
+ sage: IntegerVectors(n=5).rank([5,0])
952
+ 1
953
+ sage: IntegerVectors(n=5).rank([3,2])
954
+ 3
955
+ """
956
+ if sum (x ) != self .n :
957
+ raise ValueError ("argument is not a member of IntegerVectors({},{})" .format (self .n , None ))
958
+
959
+ n , k , s = self .n , len (x ), 0
960
+ r = binomial (k + n - 1 , n + 1 )
961
+ for i in range (k - 1 ):
962
+ s += x [k - 1 - i ]
963
+ r += binomial (s + i , i + 1 )
964
+ return r
965
+
966
+ def unrank (self , x ):
967
+ """
968
+ Return the element at given rank x.
969
+
970
+ INPUT:
971
+
972
+ - ``x`` -- an integer.
973
+
974
+ EXAMPLES::
975
+
976
+ sage: IntegerVectors(n=5).unrank(2)
977
+ [4, 1]
978
+ sage: IntegerVectors(n=10).unrank(10)
979
+ [1, 9]
980
+ """
981
+ rtn = [self .n ]
982
+ while self .rank (rtn ) <= x :
983
+ rtn .append (0 )
984
+ rtn .pop ()
985
+
986
+ return IntegerVectors ._unrank_helper (self , x , rtn )
987
+
988
+ def cardinality (self ):
989
+ """
990
+ Return the cardinality of ``self``.
991
+
992
+ EXAMPLES::
993
+
994
+ sage: IntegerVectors(n=0).cardinality()
995
+ 1
996
+ sage: IntegerVectors(n=10).cardinality()
997
+ +Infinity
998
+ """
999
+ if self .n == 0 :
1000
+ return Integer (1 )
1001
+ return PlusInfinity ()
1002
+
901
1003
902
1004
class IntegerVectors_k (UniqueRepresentation , IntegerVectors ):
903
1005
"""
@@ -912,7 +1014,10 @@ def __init__(self, k):
912
1014
sage: TestSuite(IV).run()
913
1015
"""
914
1016
self .k = k
915
- IntegerVectors .__init__ (self , category = InfiniteEnumeratedSets ())
1017
+ if self .k == 0 :
1018
+ IntegerVectors .__init__ (self , category = EnumeratedSets ())
1019
+ else :
1020
+ IntegerVectors .__init__ (self , category = InfiniteEnumeratedSets ())
916
1021
917
1022
def _repr_ (self ):
918
1023
"""
@@ -968,6 +1073,75 @@ def __contains__(self, x):
968
1073
return False
969
1074
return len (x ) == self .k
970
1075
1076
+ def rank (self , x ):
1077
+ """
1078
+ Return the rank of a given element.
1079
+
1080
+ INPUT:
1081
+
1082
+ - ``x`` -- a list with ``len(x) == k``
1083
+
1084
+ EXAMPLES::
1085
+
1086
+ sage: IntegerVectors(k=5).rank([0,0,0,0,0])
1087
+ 0
1088
+ sage: IntegerVectors(k=5).rank([1,1,0,0,0])
1089
+ 7
1090
+ """
1091
+ if len (x ) != self .k :
1092
+ raise ValueError ("argument is not a member of IntegerVectors({},{})" .format (None , self .k ))
1093
+
1094
+ n , k , s = sum (x ), self .k , 0
1095
+ r = binomial (n + k - 1 , k )
1096
+ for i in range (k - 1 ):
1097
+ s += x [k - 1 - i ]
1098
+ r += binomial (s + i , i + 1 )
1099
+ return r
1100
+
1101
+ def unrank (self , x ):
1102
+ """
1103
+ Return the element at given rank x.
1104
+
1105
+ INPUT:
1106
+
1107
+ - ``x`` -- an integer such that x < self.cardinality()``
1108
+
1109
+ EXAMPLES::
1110
+
1111
+ sage: IntegerVectors(k=5).unrank(10)
1112
+ [1, 0, 0, 0, 1]
1113
+ sage: IntegerVectors(k=5).unrank(15)
1114
+ [0, 0, 2, 0, 0]
1115
+ sage: IntegerVectors(k=0).unrank(0)
1116
+ []
1117
+ """
1118
+ if self .k == 0 and x != 0 :
1119
+ raise IndexError (f"Index { x } is out of range for the IntegerVector." )
1120
+ rtn = [0 ]* self .k
1121
+ if self .k == 0 and x == 0 :
1122
+ return rtn
1123
+
1124
+ while self .rank (rtn ) <= x :
1125
+ rtn [0 ] += 1
1126
+ rtn [0 ] -= 1
1127
+
1128
+ return IntegerVectors ._unrank_helper (self , x , rtn )
1129
+
1130
+ def cardinality (self ):
1131
+ """
1132
+ Return the cardinality of ``self``.
1133
+
1134
+ EXAMPLES::
1135
+
1136
+ sage: IntegerVectors(k=0).cardinality()
1137
+ 1
1138
+ sage: IntegerVectors(k=10).cardinality()
1139
+ +Infinity
1140
+ """
1141
+ if self .k == 0 :
1142
+ return Integer (1 )
1143
+ return PlusInfinity ()
1144
+
971
1145
972
1146
class IntegerVectors_nk (UniqueRepresentation , IntegerVectors ):
973
1147
"""
@@ -1010,11 +1184,11 @@ def _list_rec(self, n, k):
1010
1184
res = []
1011
1185
1012
1186
if k == 1 :
1013
- return [ (n , ) ]
1187
+ return [(n , )]
1014
1188
1015
1189
for nbar in range (n + 1 ):
1016
1190
n_diff = n - nbar
1017
- for rest in self ._list_rec ( nbar , k - 1 ):
1191
+ for rest in self ._list_rec (nbar , k - 1 ):
1018
1192
res .append ((n_diff ,) + rest )
1019
1193
return res
1020
1194
@@ -1153,17 +1327,49 @@ def rank(self, x):
1153
1327
if x not in self :
1154
1328
raise ValueError ("argument is not a member of IntegerVectors({},{})" .format (self .n , self .k ))
1155
1329
1156
- n = self .n
1157
- k = self .k
1158
-
1159
- r = 0
1330
+ k , s , r = self .k , 0 , 0
1160
1331
for i in range (k - 1 ):
1161
- k -= 1
1162
- n -= x [i ]
1163
- r += binomial (k + n - 1 , k )
1164
-
1332
+ s += x [k - 1 - i ]
1333
+ r += binomial (s + i , i + 1 )
1165
1334
return r
1166
1335
1336
+ def unrank (self , x ):
1337
+ """
1338
+ Return the element at given rank x.
1339
+
1340
+ INPUT:
1341
+
1342
+ - ``x`` -- an integer such that ``x < self.cardinality()``
1343
+
1344
+ EXAMPLES::
1345
+
1346
+ sage: IntegerVectors(4,5).unrank(30)
1347
+ [1, 0, 1, 0, 2]
1348
+ sage: IntegerVectors(2,3).unrank(5)
1349
+ [0, 0, 2]
1350
+ """
1351
+ if x >= self .cardinality ():
1352
+ raise IndexError (f"Index { x } is out of range for the IntegerVector." )
1353
+ rtn = [0 ]* self .k
1354
+ rtn [0 ] = self .n
1355
+ return IntegerVectors ._unrank_helper (self , x , rtn )
1356
+
1357
+ def cardinality (self ):
1358
+ """
1359
+ Return the cardinality of ``self``.
1360
+
1361
+ EXAMPLES::
1362
+
1363
+ sage: IntegerVectors(3,5).cardinality()
1364
+ 35
1365
+ sage: IntegerVectors(99, 3).cardinality()
1366
+ 5050
1367
+ sage: IntegerVectors(10^9 - 1, 3).cardinality()
1368
+ 500000000500000000
1369
+ """
1370
+ n , k = self .n , self .k
1371
+ return Integer (binomial (n + k - 1 , n ))
1372
+
1167
1373
1168
1374
class IntegerVectors_nnondescents (UniqueRepresentation , IntegerVectors ):
1169
1375
r"""
@@ -1320,11 +1526,11 @@ def __init__(self, n=None, k=None, **constraints):
1320
1526
category = FiniteEnumeratedSets ()
1321
1527
else :
1322
1528
category = EnumeratedSets ()
1323
- elif k is not None and 'max_part' in constraints : # n is None
1529
+ elif k is not None and 'max_part' in constraints : # n is None
1324
1530
category = FiniteEnumeratedSets ()
1325
1531
else :
1326
1532
category = EnumeratedSets ()
1327
- IntegerVectors .__init__ (self , category = category ) # placeholder category
1533
+ IntegerVectors .__init__ (self , category = category ) # placeholder category
1328
1534
1329
1535
def _repr_ (self ):
1330
1536
"""
0 commit comments