Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/integer_vector_weighted.py
8815 views
1
"""
2
Weighted Integer Vectors
3
4
AUTHORS:
5
6
- Mike Hansen (2007): initial version, ported from MuPAD-Combinat
7
- Nicolas M. Thiery (2010-10-30): WeightedIntegerVectors(weights) + cleanup
8
9
.. WARNING::
10
11
The list(self) function in this file used the :class:`Permutation` class improperly, returning
12
a list of, generally speaking, invalid permutations (repeated entries, including 0).
13
"""
14
#*****************************************************************************
15
# Copyright (C) 2007 Mike Hansen <[email protected]>
16
# 2010 Nicolas M. Thiery <nthiery at users.sf.net>
17
#
18
# Distributed under the terms of the GNU General Public License (GPL)
19
#
20
# http://www.gnu.org/licenses/
21
#*****************************************************************************
22
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
23
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
24
from sage.categories.sets_with_grading import SetsWithGrading
25
from __builtin__ import list as builtinlist
26
from sage.rings.integer import Integer
27
from sage.structure.unique_representation import UniqueRepresentation
28
from sage.structure.parent import Parent
29
from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
30
from sage.combinat.words.word import Word
31
from permutation import Permutation
32
33
def WeightedIntegerVectors(n = None, weight = None):
34
"""
35
Returns the combinatorial class of integer vectors of ``n``
36
weighted by ``weight``, that is, the nonnegative integer vectors
37
`(v_1,\\dots,v_{length(weight)})` satisfying `\\sum_i v_i
38
weight[i]==n`.
39
40
INPUT:
41
42
- ``n`` -- a non negative integer (optional)
43
44
- ``weight`` -- a tuple (or list or iterable) of positive integers
45
46
EXAMPLES::
47
48
sage: WeightedIntegerVectors(8, [1,1,2])
49
Integer vectors of 8 weighted by [1, 1, 2]
50
sage: WeightedIntegerVectors(8, [1,1,2]).first()
51
[0, 0, 4]
52
sage: WeightedIntegerVectors(8, [1,1,2]).last()
53
[8, 0, 0]
54
sage: WeightedIntegerVectors(8, [1,1,2]).cardinality()
55
25
56
sage: WeightedIntegerVectors(8, [1,1,2]).random_element()
57
[1, 1, 3]
58
59
sage: WeightedIntegerVectors([1,1,2])
60
Integer vectors weighted by [1, 1, 2]
61
sage: WeightedIntegerVectors([1,1,2]).cardinality()
62
+Infinity
63
sage: WeightedIntegerVectors([1,1,2]).first()
64
[0, 0, 0]
65
66
TESTS::
67
68
sage: WeightedIntegerVectors(None,None)
69
Traceback (most recent call last):
70
...
71
ValueError: weights should be specified
72
73
.. TODO::
74
75
should the order of the arguments ``n`` and ``weight`` be
76
exchanged to simplify the logic ?
77
"""
78
if weight is None and n is not None:
79
weight = n
80
n = None
81
if weight is None:
82
raise ValueError("weights should be specified")
83
weight = tuple(weight)
84
if n is None:
85
return WeightedIntegerVectors_all(weight)
86
else:
87
return WeightedIntegerVectors_nweight(n, weight)
88
89
class WeightedIntegerVectors_all(DisjointUnionEnumeratedSets):
90
r"""
91
Set of weighted integer vectors.
92
93
EXAMPLES::
94
95
sage: W = WeightedIntegerVectors([3,1,1,2,1]); W
96
Integer vectors weighted by [3, 1, 1, 2, 1]
97
sage: W.cardinality()
98
+Infinity
99
100
sage: W12 = W.graded_component(12)
101
sage: W12.an_element()
102
[4, 0, 0, 0, 0]
103
sage: W12.last()
104
[0, 12, 0, 0, 0]
105
sage: W12.cardinality()
106
441
107
sage: for w in W12: print w
108
[4, 0, 0, 0, 0]
109
[3, 0, 0, 1, 1]
110
[3, 0, 1, 1, 0]
111
...
112
[0, 11, 1, 0, 0]
113
[0, 12, 0, 0, 0]
114
"""
115
def __init__(self, weights):
116
"""
117
TESTS::
118
119
sage: C = WeightedIntegerVectors([2,1,3])
120
sage: C.__class__
121
<class 'sage.combinat.integer_vector_weighted.WeightedIntegerVectors_all_with_category'>
122
sage: C.category()
123
Join of Category of infinite enumerated sets and Category of sets with grading
124
sage: TestSuite(C).run()
125
"""
126
self._weights = weights
127
from sage.sets.all import Family, NonNegativeIntegers
128
# Use "partial" to make the basis function (with the weights
129
# argument specified) pickleable. Otherwise, it seems to
130
# cause problems...
131
from functools import partial
132
F = Family(NonNegativeIntegers(), partial(WeightedIntegerVectors, weight = weights))
133
DisjointUnionEnumeratedSets.__init__(self, F, facade=True, keepkey=False,
134
category = (SetsWithGrading(), InfiniteEnumeratedSets()))
135
136
def _repr_(self):
137
"""
138
EXAMPLES::
139
140
sage: WeightedIntegerVectors([2,1,3])
141
Integer vectors weighted by [2, 1, 3]
142
"""
143
return "Integer vectors weighted by %s"%list(self._weights)
144
145
def __contains__(self, x):
146
"""
147
EXAMPLES::
148
149
sage: [] in WeightedIntegerVectors([])
150
True
151
sage: [3,0,0] in WeightedIntegerVectors([2,1,1])
152
True
153
sage: [3,0] in WeightedIntegerVectors([2,1,1])
154
False
155
sage: [3,-1,0] in WeightedIntegerVectors([2,1,1])
156
False
157
"""
158
return isinstance(x, (builtinlist, Permutation)) and \
159
len(x) == len(self._weights) and \
160
all(isinstance(i, (int, Integer)) and i>=0 for i in x)
161
162
def subset(self, size = None):
163
"""
164
EXAMPLES::
165
166
sage: C = WeightedIntegerVectors([2,1,3])
167
sage: C.subset(4)
168
Integer vectors of 4 weighted by [2, 1, 3]
169
"""
170
if size is None:
171
return self
172
return self._family[size]
173
174
def grading(self, x): # or degree / grading
175
"""
176
EXAMPLES::
177
178
sage: C = WeightedIntegerVectors([2,1,3])
179
sage: C.grading((2,1,1))
180
8
181
"""
182
return sum([exp*deg for exp,deg in zip(x, self._weights)])
183
184
class WeightedIntegerVectors_nweight(UniqueRepresentation, Parent):
185
def __init__(self, n, weight):
186
"""
187
TESTS::
188
189
sage: C = WeightedIntegerVectors(8, [1,1,2])
190
sage: C.__class__
191
<class 'sage.combinat.integer_vector_weighted.WeightedIntegerVectors_nweight_with_category'>
192
sage: TestSuite(C).run()
193
"""
194
Parent.__init__(self, category = FiniteEnumeratedSets())
195
self._n = n
196
self._weights = weight
197
198
def _repr_(self):
199
"""
200
TESTS::
201
202
sage: repr(WeightedIntegerVectors(8, [1,1,2]))
203
'Integer vectors of 8 weighted by [1, 1, 2]'
204
"""
205
return "Integer vectors of %s weighted by %s"%(self._n, list(self._weights))
206
207
def __contains__(self, x):
208
"""
209
EXAMPLES::
210
211
sage: [] in WeightedIntegerVectors(0, [])
212
True
213
sage: [] in WeightedIntegerVectors(1, [])
214
False
215
sage: [3,0,0] in WeightedIntegerVectors(6, [2,1,1])
216
True
217
sage: [1] in WeightedIntegerVectors(1, [1])
218
True
219
sage: [1] in WeightedIntegerVectors(2, [2])
220
True
221
sage: [2] in WeightedIntegerVectors(4, [2])
222
True
223
sage: [2, 0] in WeightedIntegerVectors(4, [2, 2])
224
True
225
sage: [2, 1] in WeightedIntegerVectors(4, [2, 2])
226
False
227
sage: [2, 1] in WeightedIntegerVectors(6, [2, 2])
228
True
229
sage: [2, 1, 0] in WeightedIntegerVectors(6, [2, 2])
230
False
231
sage: [0] in WeightedIntegerVectors(0, [])
232
False
233
"""
234
if not isinstance(x, (builtinlist, Permutation)):
235
return False
236
if len(self._weights) != len(x):
237
return False
238
s = 0
239
for i in range(len(x)):
240
if not isinstance(x[i], (int, Integer)):
241
return False
242
s += x[i]*self._weights[i]
243
if s != self._n:
244
return False
245
246
return True
247
248
def _recfun(self, n, l):
249
"""
250
EXAMPLES::
251
252
sage: w = WeightedIntegerVectors(3, [2,1,1])
253
sage: list(w._recfun(3, [1,1,2]))
254
[[0, 1, 1], [1, 0, 1], [0, 3, 0], [1, 2, 0], [2, 1, 0], [3, 0, 0]]
255
"""
256
w = l[-1]
257
l = l[:-1]
258
if l == []:
259
d = int(n) / int(w)
260
if n % w == 0:
261
yield [d]
262
# Otherwise: bad branch
263
return
264
265
for d in range(int(n)/int(w), -1, -1):
266
for x in self._recfun(n-d*w, l):
267
yield x + [d]
268
269
def __iter__(self):
270
"""
271
TESTS::
272
273
sage: WeightedIntegerVectors(7, [2,2]).list()
274
[]
275
sage: WeightedIntegerVectors(3, [2,1,1]).list()
276
[[1, 0, 1], [1, 1, 0], [0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0]]
277
278
::
279
280
sage: ivw = [ WeightedIntegerVectors(k, [1,1,1]) for k in range(11) ]
281
sage: iv = [ IntegerVectors(k, 3) for k in range(11) ]
282
sage: all( [ sorted(iv[k].list()) == sorted(ivw[k].list()) for k in range(11) ] )
283
True
284
285
::
286
287
sage: ivw = [ WeightedIntegerVectors(k, [2,3,7]) for k in range(11) ]
288
sage: all( [ i.cardinality() == len(i.list()) for i in ivw] )
289
True
290
"""
291
if len(self._weights) == 0:
292
if self._n == 0:
293
yield []
294
return
295
296
perm = Word(self._weights).standard_permutation()
297
l = [x for x in sorted(self._weights)]
298
for x in self._recfun(self._n, l):
299
yield perm.action(x)
300
#_left_to_right_multiply_on_right(Permutation(x))
301
302