Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/tests/arxiv_0812_2725.py
4108 views
1
r"""
2
Sage code for computing k-distant crossing numbers.
3
4
This code accompanies the article arxiv:0812.2725; see
5
http://arxiv.org/abs/0812.2725. It is being submitted because of a
6
suggestion from
7
http://groups.google.com/group/sage-support/msg/3ea7ed2eeab0824a.
8
9
Right now, this code only computes k-dcrossings. If you are only
10
interested in the distribution, this is good enough because the extended
11
Kasraoui-Zeng involution tells us the distribution of k-dcrossings and
12
k-dnestings is symmetric. It would be nice, though, to have a function
13
which actually performed that involution.
14
15
AUTHORS:
16
-- Dan Drake (2008-12-15): initial version.
17
18
EXAMPLES:
19
20
The example given in the paper. Note that in this format, we omit fixed
21
points since they cannot create any sort of crossing.
22
23
sage: from sage.tests.arxiv_0812_2725 import *
24
sage: dcrossing([(1,5), (2,4), (4,9), (6,12), (7,10), (10,11)])
25
3
26
27
"""
28
29
#*****************************************************************************
30
# Copyright (C) 2008 Dan Drake <[email protected]>
31
#
32
# This program is free software: you can redistribute it and/or modify
33
# it under the terms of the GNU General Public License as published by
34
# the Free Software Foundation, either version 2 of the License, or (at
35
# your option) any later version.
36
#
37
# See http://www.gnu.org/licenses/.
38
#*****************************************************************************
39
40
from sage.combinat.set_partition import SetPartitions as SetPartitions
41
42
def CompleteMatchings(n):
43
"""
44
Return a generator for the complete matchings of the set [1..n].
45
46
INPUT:
47
n -- nonnegative integer
48
49
OUTPUT:
50
A generator for the complete matchings of the set [1..n], or,
51
what is basically the same thing, complete matchings of the
52
graph K_n. Each complete matching is represented by a list of
53
2-element tuples.
54
55
EXAMPLES:
56
There are 3 complete matchings on 4 vertices:
57
sage: from sage.tests.arxiv_0812_2725 import *
58
sage: [m for m in CompleteMatchings(4)]
59
[[(3, 4), (1, 2)], [(2, 4), (1, 3)], [(2, 3), (1, 4)]]
60
61
There are no complete matchings on an odd number of vertices; the
62
number of complete matchings on an even number of vertices is a
63
double factorial:
64
sage: from sage.tests.arxiv_0812_2725 import *
65
sage: [len([m for m in CompleteMatchings(n)]) for n in [0..8]]
66
[1, 0, 1, 0, 3, 0, 15, 0, 105]
67
68
The exact behavior of CompleteMatchings(n) if n is not a nonnegative
69
integer depends on what [1..n] returns, and also on what range(1,
70
len([1..n])) is.
71
72
"""
73
for m in matchingsset(range(1, n+1)): yield m
74
75
def matchingsset(L):
76
"""
77
Return a generator for complete matchings of the sequence L.
78
79
This is not really meant to be called directly, but rather by
80
CompleteMatchings().
81
82
INPUT:
83
L -- a sequence. Lists, tuples, et cetera; anything that
84
supports len() and slicing should work.
85
86
OUTPUT:
87
A generator for complete matchings on K_n, where n is the length
88
of L and vertices are labeled by elements of L. Each matching is
89
represented by a list of 2-element tuples.
90
91
EXAMPLES:
92
sage: from sage.tests.arxiv_0812_2725 import *
93
sage: [m for m in matchingsset(('a', 'b', 'c', 'd'))]
94
[[('c', 'd'), ('a', 'b')], [('b', 'd'), ('a', 'c')], [('b', 'c'), ('a', 'd')]]
95
96
There's only one matching of the empty set/list/tuple: the empty
97
matching.
98
99
sage: [m for m in matchingsset(())]
100
[[]]
101
"""
102
if len(L) == 0:
103
yield []
104
else:
105
for k in range(1, len(L)):
106
for m in matchingsset(L[1:k] + L[k+1:]):
107
yield m + [(L[0], L[k])]
108
109
def dcrossing(m_):
110
"""Return the largest k for which the given matching or set
111
partition has a k-distant crossing.
112
113
INPUT:
114
m -- a matching or set partition, as a list of 2-element tuples
115
representing the edges. You'll need to call setp_to_edges() on
116
the objects returned by SetPartitions() to put them into the
117
proper format.
118
119
OUTPUT:
120
The largest k for which the object has a k-distant crossing.
121
Matchings and set partitions with no crossings at all yield -1.
122
123
EXAMPLES:
124
The main example from the paper:
125
sage: from sage.tests.arxiv_0812_2725 import *
126
sage: dcrossing(setp_to_edges(Set(map(Set, [[1,5],[2,4,9],[3],[6,12],[7,10,11],[8]]))))
127
3
128
129
A matching example:
130
131
sage: from sage.tests.arxiv_0812_2725 import *
132
sage: dcrossing([(4, 7), (3, 6), (2, 5), (1, 8)])
133
2
134
135
TESTS:
136
The empty matching and set partition are noncrossing:
137
sage: dcrossing([])
138
-1
139
sage: dcrossing(Set([]))
140
-1
141
142
One edge:
143
sage: dcrossing([Set((1,2))])
144
-1
145
sage: dcrossing(Set([Set((1,2))]))
146
-1
147
148
Set partition with block of size >= 3 is always at least
149
0-dcrossing:
150
sage: dcrossing(setp_to_edges(Set([Set((1,2,3))])))
151
0
152
"""
153
d = -1
154
m = list(m_)
155
while len(m) > 0:
156
e1_ = m.pop()
157
for e2_ in m:
158
e1, e2 = sorted(e1_), sorted(e2_)
159
if (e1[0] < e2[0] and e2[0] <= e1[1] and e1[1] < e2[1] and
160
e1[1] - e2[0] > d):
161
d = e1[1] - e2[0]
162
if (e2[0] < e1[0] and e1[0] <= e2[1] and e2[1] < e1[1] and
163
e2[1] - e1[0] > d):
164
d = e2[1] - e1[0]
165
return d
166
167
def setp_to_edges(p):
168
"""
169
Transform a set partition into a list of edges.
170
171
INPUT:
172
p -- a Sage set partition.
173
174
OUTPUT:
175
A list of non-loop edges of the set partition. As this code just
176
works with crossings, we can ignore the loops.
177
178
EXAMPLE:
179
The main example from the paper:
180
sage: from sage.tests.arxiv_0812_2725 import *
181
sage: setp_to_edges(Set(map(Set, [[1,5],[2,4,9],[3],[6,12],[7,10,11],[8]])))
182
[[7, 10], [10, 11], [2, 4], [4, 9], [1, 5], [6, 12]]
183
"""
184
q = [ sorted(list(b)) for b in p ]
185
ans = []
186
for b in q:
187
for n in range(len(b) - 1):
188
ans.append(b[n:n+2])
189
return ans
190
191
def dcrossvec_setp(n):
192
"""
193
Return a list with the distribution of k-dcrossings on set partitions of [1..n].
194
195
INPUT:
196
n -- a nonnegative integer.
197
198
OUTPUT:
199
A list whose k'th entry is the number of set partitions p for
200
which dcrossing(p) = k. For example, let L = dcrossvec_setp(3).
201
We have L = [1, 0, 4]. L[0] is 1 because there's 1 partition of
202
[1..3] that has 0-dcrossing: [(1, 2, 3)].
203
204
One tricky bit is that noncrossing matchings get put at the end,
205
because L[-1] is the last element of the list. Above, we have
206
L[-1] = 4 because the other four set partitions are all
207
d-noncrossing. Because of this, you should not think of the last
208
element of the list as having index n-1, but rather -1.
209
210
EXAMPLES:
211
sage: from sage.tests.arxiv_0812_2725 import *
212
sage: dcrossvec_setp(3)
213
[1, 0, 4]
214
215
sage: dcrossvec_setp(4)
216
[5, 1, 0, 9]
217
218
The one set partition of 1 element is noncrossing, so the last
219
element of the list is 1:
220
sage: dcrossvec_setp(1)
221
[1]
222
"""
223
vec = [0] * n
224
for p in SetPartitions(n):
225
vec[dcrossing(setp_to_edges(p))] += 1
226
return vec
227
228
def dcrossvec_cm(n):
229
"""
230
Return a list with the distribution of k-dcrossings on complete matchings on n vertices.
231
232
INPUT:
233
n -- a nonnegative integer.
234
235
OUTPUT:
236
A list whose k'th entry is the number of complete matchings m
237
for which dcrossing(m) = k. For example, let L =
238
dcrossvec_cm(4). We have L = [0, 1, 0, 2]. L[1] is 1 because
239
there's one matching on 4 vertices that is 1-dcrossing: [(2, 4),
240
(1, 3)]. L[0] is zero because dcrossing() returns the *largest*
241
k for which the matching has a dcrossing, and 0-dcrossing is
242
equivalent to 1-dcrossing for complete matchings.
243
244
One tricky bit is that noncrossing matchings get put at the end,
245
because L[-1] is the last element of the list. Because of this, you
246
should not think of the last element of the list as having index
247
n-1, but rather -1.
248
249
If n is negative, you get silly results. Don't use them in your
250
next paper. :)
251
252
EXAMPLES:
253
The single complete matching on 2 vertices has no crossings, so the
254
only nonzero entry of the list (the last entry) is 1:
255
sage: from sage.tests.arxiv_0812_2725 import *
256
sage: dcrossvec_cm(2)
257
[0, 1]
258
259
Similarly, the empty matching has no crossings:
260
sage: dcrossvec_cm(0)
261
[1]
262
263
For odd n, there are no complete matchings, so the list has all
264
zeros:
265
sage: dcrossvec_cm(5)
266
[0, 0, 0, 0, 0]
267
268
sage: dcrossvec_cm(4)
269
[0, 1, 0, 2]
270
"""
271
vec = [0] * max(n, 1)
272
for m in CompleteMatchings(n):
273
vec[dcrossing(m)] += 1
274
return vec
275
276
def tablecolumn(n, k):
277
"""
278
Return column n of Table 1 or 2 from the paper arxiv:0812.2725.
279
280
INPUT:
281
n -- positive integer.
282
283
k -- integer for which table you want: Table 1 is complete
284
matchings, Table 2 is set partitions.
285
286
OUTPUT:
287
The n'th column of the table as a list. This is basically just the
288
partial sums of dcrossvec_{cm,setp}(n).
289
290
table2column(1, 2) incorrectly returns [], instead of [1], but you
291
probably don't need this function to work through n = 1.
292
293
EXAMPLES:
294
Complete matchings:
295
sage: from sage.tests.arxiv_0812_2725 import *
296
sage: tablecolumn(2, 1)
297
[1]
298
299
sage: tablecolumn(6, 1)
300
[5, 5, 11, 14, 15]
301
302
Set partitions:
303
sage: tablecolumn(5, 2)
304
[21, 42, 51, 52]
305
306
sage: tablecolumn(2, 2)
307
[2]
308
"""
309
if k == 1:
310
v = dcrossvec_cm(n)
311
else:
312
v = dcrossvec_setp(n)
313
i = v[-1]
314
return [i + sum(v[:k]) for k in range(len(v) - 1)]
315
316