Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/alternating_sign_matrix.py
4069 views
1
r"""
2
Alternating Sign Matrices
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2007 Mike Hansen <[email protected]>,
6
#
7
# Distributed under the terms of the GNU General Public License (GPL)
8
#
9
# This code is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
# General Public License for more details.
13
#
14
# The full text of the GPL is available at:
15
#
16
# http://www.gnu.org/licenses/
17
#*****************************************************************************
18
19
from combinat import CombinatorialClass
20
from sage.matrix.matrix_space import MatrixSpace
21
from sage.rings.all import ZZ, factorial
22
from sage.sets.set import Set
23
from sage.misc.misc import prod
24
import copy
25
26
def from_contre_tableau(comps):
27
"""
28
Returns an alternating sign matrix from a contretableaux.
29
30
TESTS::
31
32
sage: import sage.combinat.alternating_sign_matrix as asm
33
sage: asm.from_contre_tableau([[1, 2, 3], [1, 2], [1]])
34
[0 0 1]
35
[0 1 0]
36
[1 0 0]
37
sage: asm.from_contre_tableau([[1, 2, 3], [2, 3], [3]])
38
[1 0 0]
39
[0 1 0]
40
[0 0 1]
41
"""
42
n = len(comps)
43
MS = MatrixSpace(ZZ, n)
44
M = [ [0 for _ in range(n)] for _ in range(n) ]
45
46
previous_set = Set([])
47
48
for col in range(n-1, -1, -1):
49
s = Set( comps[col] )
50
for x in s - previous_set:
51
M[x-1][col] = 1
52
53
for x in previous_set - s:
54
M[x-1][col] = -1
55
56
previous_set = s
57
58
return MS(M)
59
60
def AlternatingSignMatrices(n):
61
r"""
62
Returns the combinatorial class of alternating sign matrices of
63
size n.
64
65
EXAMPLES::
66
67
sage: a2 = AlternatingSignMatrices(2); a2
68
Alternating sign matrices of size 2
69
sage: for a in a2: print a, "-\n"
70
[0 1]
71
[1 0]
72
-
73
[1 0]
74
[0 1]
75
-
76
"""
77
return AlternatingSignMatrices_n(n)
78
79
class AlternatingSignMatrices_n(CombinatorialClass):
80
def __init__(self, n):
81
"""
82
TESTS::
83
84
sage: a2 = AlternatingSignMatrices(2); a2
85
Alternating sign matrices of size 2
86
sage: a2 == loads(dumps(a2))
87
True
88
"""
89
self.n = n
90
91
def __repr__(self):
92
"""
93
TESTS::
94
95
sage: repr(AlternatingSignMatrices(2))
96
'Alternating sign matrices of size 2'
97
"""
98
return "Alternating sign matrices of size %s"%self.n
99
100
def cardinality(self):
101
"""
102
TESTS::
103
104
sage: [ AlternatingSignMatrices(n).cardinality() for n in range(0, 11)]
105
[1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]
106
107
::
108
109
sage: asms = [ AlternatingSignMatrices(n) for n in range(6) ]
110
sage: all( [ asm.cardinality() == len(asm.list()) for asm in asms] )
111
True
112
"""
113
return prod( [ factorial(3*k+1)/factorial(self.n+k) for k in range(self.n)] )
114
115
def __iter__(self):
116
"""
117
TESTS::
118
119
sage: AlternatingSignMatrices(0).list() # indirect doctest
120
[[]]
121
sage: AlternatingSignMatrices(1).list() # indirect doctest
122
[[1]]
123
sage: map(list, AlternatingSignMatrices(2).list()) # indirect doctest
124
[[(0, 1), (1, 0)], [(1, 0), (0, 1)]]
125
sage: map(list, AlternatingSignMatrices(3).list()) # indirect doctest
126
[[(0, 0, 1), (0, 1, 0), (1, 0, 0)],
127
[(0, 1, 0), (0, 0, 1), (1, 0, 0)],
128
[(0, 0, 1), (1, 0, 0), (0, 1, 0)],
129
[(0, 1, 0), (1, -1, 1), (0, 1, 0)],
130
[(0, 1, 0), (1, 0, 0), (0, 0, 1)],
131
[(1, 0, 0), (0, 0, 1), (0, 1, 0)],
132
[(1, 0, 0), (0, 1, 0), (0, 0, 1)]]
133
"""
134
for z in ContreTableaux(self.n):
135
yield from_contre_tableau(z)
136
137
138
def ContreTableaux(n):
139
"""
140
Returns the combinatorial class of contre tableaux of size n.
141
142
EXAMPLES::
143
144
sage: ct4 = ContreTableaux(4); ct4
145
Contre tableaux of size 4
146
sage: ct4.cardinality()
147
42
148
sage: ct4.first()
149
[[1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]
150
sage: ct4.last()
151
[[1, 2, 3, 4], [2, 3, 4], [3, 4], [4]]
152
sage: ct4.random_element()
153
[[1, 2, 3, 4], [1, 2, 3], [1, 3], [3]]
154
"""
155
return ContreTableaux_n(n)
156
157
class ContreTableaux_n(CombinatorialClass):
158
def __init__(self, n):
159
"""
160
TESTS::
161
162
sage: ct2 = ContreTableaux(2); ct2
163
Contre tableaux of size 2
164
sage: ct2 == loads(dumps(ct2))
165
True
166
"""
167
self.n = n
168
169
def __repr__(self):
170
"""
171
TESTS::
172
173
sage: repr(ContreTableaux(2))
174
'Contre tableaux of size 2'
175
"""
176
return "Contre tableaux of size %s"%self.n
177
178
def cardinality(self):
179
"""
180
TESTS::
181
182
sage: [ ContreTableaux(n).cardinality() for n in range(0, 11)]
183
[1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]
184
"""
185
return prod( [ factorial(3*k+1)/factorial(self.n+k) for k in range(self.n)] )
186
187
def _iterator_rec(self, i):
188
"""
189
TESTS::
190
191
sage: c = ContreTableaux(2)
192
sage: list(c._iterator_rec(0))
193
[[]]
194
sage: list(c._iterator_rec(1))
195
[[[1, 2]]]
196
sage: list(c._iterator_rec(2))
197
[[[1, 2], [1]], [[1, 2], [2]]]
198
"""
199
if i == 0:
200
yield []
201
elif i == 1:
202
yield [range(1, self.n+1)]
203
else:
204
for columns in self._iterator_rec(i-1):
205
previous_column = columns[-1]
206
for column in _next_column_iterator(previous_column, len(previous_column)-1):
207
yield columns + [ column ]
208
209
def __iter__(self):
210
"""
211
TESTS::
212
213
sage: ContreTableaux(0).list() #indirect test
214
[[]]
215
sage: ContreTableaux(1).list() #indirect test
216
[[[1]]]
217
sage: ContreTableaux(2).list() #indirect test
218
[[[1, 2], [1]], [[1, 2], [2]]]
219
sage: ContreTableaux(3).list() #indirect test
220
[[[1, 2, 3], [1, 2], [1]],
221
[[1, 2, 3], [1, 2], [2]],
222
[[1, 2, 3], [1, 3], [1]],
223
[[1, 2, 3], [1, 3], [2]],
224
[[1, 2, 3], [1, 3], [3]],
225
[[1, 2, 3], [2, 3], [2]],
226
[[1, 2, 3], [2, 3], [3]]]
227
"""
228
229
for z in self._iterator_rec(self.n):
230
yield z
231
232
233
234
def _next_column_iterator(previous_column, height, i = None):
235
"""
236
Returns a generator for all columns of height height properly
237
filled from row 1 to i
238
239
TESTS::
240
241
sage: import sage.combinat.alternating_sign_matrix as asm
242
sage: list(asm._next_column_iterator([1], 0))
243
[[]]
244
sage: list(asm._next_column_iterator([1,5],1))
245
[[1], [2], [3], [4], [5]]
246
sage: list(asm._next_column_iterator([1,4,5],2))
247
[[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
248
"""
249
if i is None:
250
i = height
251
if i == 0:
252
yield [-1]*height
253
else:
254
for column in _next_column_iterator(previous_column, height, i-1):
255
min_value = previous_column[i-1]
256
if i > 1:
257
min_value = max(min_value, column[i-2]+1)
258
for value in range(min_value, previous_column[i]+1):
259
c = copy.copy(column)
260
c[i-1] = value
261
yield c
262
263
def _previous_column_iterator(column, height, max_value):
264
"""
265
TESTS::
266
267
sage: import sage.combinat.alternating_sign_matrix as asm
268
sage: list(asm._previous_column_iterator([2,3], 3, 4))
269
[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
270
"""
271
new_column = [1] + column + [ max_value ] * (height - len(column))
272
return _next_column_iterator(new_column, height)
273
274
def TruncatedStaircases(n, last_column):
275
"""
276
Returns the combinatorial class of truncated staircases of size n
277
with last column last_column.
278
279
EXAMPLES::
280
281
sage: t4 = TruncatedStaircases(4, [2,3]); t4
282
Truncated staircases of size 4 with last column [2, 3]
283
sage: t4.cardinality()
284
4
285
sage: t4.first()
286
[[4, 3, 2, 1], [3, 2, 1], [3, 2]]
287
sage: t4.list()
288
[[[4, 3, 2, 1], [3, 2, 1], [3, 2]], [[4, 3, 2, 1], [4, 2, 1], [3, 2]], [[4, 3, 2, 1], [4, 3, 1], [3, 2]], [[4, 3, 2, 1], [4, 3, 2], [3, 2]]]
289
"""
290
return TruncatedStaircases_nlastcolumn(n, last_column)
291
292
class TruncatedStaircases_nlastcolumn(CombinatorialClass):
293
def __init__(self, n, last_column):
294
"""
295
TESTS::
296
297
sage: t4 = TruncatedStaircases(4, [2,3]); t4
298
Truncated staircases of size 4 with last column [2, 3]
299
sage: t4 == loads(dumps(t4))
300
True
301
"""
302
self.n = n
303
self.last_column = last_column
304
305
def __repr__(self):
306
"""
307
TESTS::
308
309
sage: repr(TruncatedStaircases(4, [2,3]))
310
'Truncated staircases of size 4 with last column [2, 3]'
311
"""
312
return "Truncated staircases of size %s with last column %s"%(self.n, self.last_column)
313
314
def _iterator_rec(self, i):
315
"""
316
TESTS::
317
318
sage: t = TruncatedStaircases(3, [2,3])
319
sage: list(t._iterator_rec(1))
320
[]
321
sage: list(t._iterator_rec(2))
322
[[[2, 3]]]
323
sage: list(t._iterator_rec(3))
324
[[[1, 2, 3], [2, 3]]]
325
"""
326
if i < len(self.last_column):
327
return
328
elif i == len(self.last_column):
329
yield [self.last_column]
330
else:
331
for columns in self._iterator_rec(i-1):
332
previous_column = columns[0]
333
for column in _previous_column_iterator(previous_column, len(previous_column)+1, self.n):
334
yield [column] + columns
335
336
def __iter__(self):
337
"""
338
EXAMPLES:::
339
340
sage: TruncatedStaircases(4, [2,3]).list() #indirect test
341
[[[4, 3, 2, 1], [3, 2, 1], [3, 2]], [[4, 3, 2, 1], [4, 2, 1], [3, 2]], [[4, 3, 2, 1], [4, 3, 1], [3, 2]], [[4, 3, 2, 1], [4, 3, 2], [3, 2]]]
342
"""
343
for z in self._iterator_rec(self.n):
344
yield map(lambda x: list(reversed(x)), z)
345
346
347
348