Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/graphs/trees.pyx
8815 views
1
r"""
2
Generation of trees
3
4
This is an implementation of the algorithm for generating trees with `n` vertices
5
(up to isomorphism) in constant time per tree described in [WRIGHT-ETAL]_.
6
7
AUTHORS:
8
9
- Ryan Dingman (2009-04-16): initial version
10
11
REFERENCES:
12
13
.. [WRIGHT-ETAL] Wright, Robert Alan; Richmond, Bruce; Odlyzko, Andrew; McKay, Brendan D.
14
Constant time generation of free trees. SIAM J. Comput. 15 (1986), no. 2,
15
540--548.
16
"""
17
18
cdef extern from "limits.h":
19
cdef int INT_MAX
20
21
include "sage/ext/stdsage.pxi"
22
23
# from networkx import MultiGraph
24
25
from sage.graphs.graph import Graph
26
from sage.graphs.base.sparse_graph cimport SparseGraph
27
28
cdef class TreeIterator:
29
r"""
30
This class iterates over all trees with n vertices (up to isomorphism).
31
32
EXAMPLES::
33
34
sage: from sage.graphs.trees import TreeIterator
35
sage: def check_trees(n):
36
... trees = []
37
... for t in TreeIterator(n):
38
... if t.is_tree() == False:
39
... return False
40
... if t.num_verts() != n:
41
... return False
42
... if t.num_edges() != n - 1:
43
... return False
44
... for tree in trees:
45
... if tree.is_isomorphic(t) == True:
46
... return False
47
... trees.append(t)
48
... return True
49
sage: print check_trees(10)
50
True
51
52
::
53
54
sage: from sage.graphs.trees import TreeIterator
55
sage: count = 0
56
sage: for t in TreeIterator(15):
57
... count += 1
58
sage: print count
59
7741
60
"""
61
62
def __init__(self, int vertices):
63
r"""
64
Initializes an iterator over all trees with `n` vertices.
65
66
EXAMPLES::
67
68
sage: from sage.graphs.trees import TreeIterator
69
sage: t = TreeIterator(100) # indirect doctest
70
sage: print t
71
Iterator over all trees with 100 vertices
72
"""
73
self.vertices = vertices
74
self.l = NULL
75
self.current_level_sequence = NULL
76
self.first_time = 1
77
78
def __dealloc__(self):
79
r"""
80
EXAMPLES::
81
82
sage: from sage.graphs.trees import TreeIterator
83
sage: t = TreeIterator(100)
84
sage: t = None # indirect doctest
85
"""
86
if self.l != NULL:
87
sage_free(self.l)
88
self.l = NULL
89
if self.current_level_sequence != NULL:
90
sage_free(self.current_level_sequence)
91
self.current_level_sequence = NULL
92
93
def __str__(self):
94
r"""
95
EXAMPLES::
96
97
sage: from sage.graphs.trees import TreeIterator
98
sage: t = TreeIterator(100)
99
sage: print t # indirect doctest
100
Iterator over all trees with 100 vertices
101
"""
102
return "Iterator over all trees with %s vertices"%(self.vertices)
103
104
def __iter__(self):
105
r"""
106
Returns an iterator over all the trees with `n` vertices.
107
108
EXAMPLES::
109
110
sage: from sage.graphs.trees import TreeIterator
111
sage: t = TreeIterator(4)
112
sage: list(iter(t))
113
[Graph on 4 vertices, Graph on 4 vertices]
114
"""
115
return self
116
117
def __next__(self):
118
r"""
119
Returns the next tree with `n` vertices
120
121
EXAMPLES::
122
123
sage: from sage.graphs.trees import TreeIterator
124
sage: T = TreeIterator(5)
125
sage: [t for t in T] # indirect doctest
126
[Graph on 5 vertices, Graph on 5 vertices, Graph on 5 vertices]
127
128
129
TESTS:
130
131
This used to be broken for trees with no vertices
132
and was fixed in :trac:`13719` ::
133
134
sage: from sage.graphs.trees import TreeIterator
135
sage: T = TreeIterator(0)
136
sage: [t for t in T] # indirect doctest
137
[Graph on 0 vertices]
138
"""
139
140
if not self.first_time and self.q == 0:
141
raise StopIteration
142
143
if self.first_time == 1:
144
if self.vertices == 0:
145
self.first_time = 0
146
self.q = 0
147
else:
148
self.l = <int *>sage_malloc(self.vertices * sizeof(int))
149
self.current_level_sequence = <int *>sage_malloc(self.vertices * sizeof(int))
150
151
if self.l == NULL or self.current_level_sequence == NULL:
152
raise MemoryError
153
154
self.generate_first_level_sequence()
155
self.first_time = 0
156
else:
157
self.generate_next_level_sequence()
158
159
cdef int i
160
cdef int vertex1
161
cdef int vertex2
162
cdef object G
163
164
# from networkx import MultiGraph
165
# G = Graph(self.vertices)
166
# cdef object XG = G._backend._nxg
167
#
168
# for i from 2 <= i <= self.vertices:
169
# vertex1 = i - 1
170
# vertex2 = self.current_level_sequence[i - 1] - 1
171
# XG.add_edge(vertex1, vertex2)
172
#
173
# return G
174
175
# Currently, c_graph does not have all the same functionality as networkx.
176
# Until it does, we can't generate graphs using the c_graph backend even
177
# though it is twice as fast (for our purposes) as networkx.
178
179
G = Graph(self.vertices, implementation='c_graph', sparse=True)
180
cdef SparseGraph SG = <SparseGraph> G._backend._cg
181
182
for i from 2 <= i <= self.vertices:
183
vertex1 = i - 1
184
vertex2 = self.current_level_sequence[i - 1] - 1
185
SG.add_arc_unsafe(vertex1, vertex2)
186
SG.add_arc_unsafe(vertex2, vertex1)
187
188
return G
189
190
cdef int generate_first_level_sequence(self):
191
r"""
192
Generates the level sequence representing the first tree with `n` vertices
193
"""
194
cdef int i
195
cdef int k
196
197
k = (self.vertices / 2) + 1
198
199
if self.vertices == 4:
200
self.p = 3
201
else:
202
self.p = self.vertices
203
self.q = self.vertices - 1
204
self.h1 = k
205
self.h2 = self.vertices
206
if self.vertices % 2 == 0:
207
self.c = self.vertices + 1
208
else:
209
self.c = INT_MAX # oo
210
211
self.r = k
212
213
for i from 1 <= i <= k:
214
self.l[i - 1] = i
215
for i from k < i <= self.vertices:
216
self.l[i - 1] = i - k + 1
217
for i from 0 <= i < self.vertices:
218
self.current_level_sequence[i] = i
219
if self.vertices > 2:
220
self.current_level_sequence[k] = 1
221
if self.vertices <= 3:
222
self.q = 0
223
224
return 0
225
226
cdef int generate_next_level_sequence(self):
227
r"""
228
Generates the level sequence representing the next tree with `n` vertices
229
"""
230
cdef int i
231
cdef int fixit = 0
232
233
cdef int needr = 0
234
cdef int needc = 0
235
cdef int needh2 = 0
236
237
cdef int n = self.vertices
238
cdef int p = self.p
239
cdef int q = self.q
240
cdef int h1 = self.h1
241
cdef int h2 = self.h2
242
cdef int c = self.c
243
cdef int r = self.r
244
cdef int *l = self.l
245
cdef int *w = self.current_level_sequence
246
247
if c == n + 1 or p == h2 and (l[h1 - 1] == l[h2 - 1] + 1 and n - h2 > r - h1 or l[h1 - 1] == l[h2 - 1] and n - h2 + 1 < r - h1):
248
if (l[r - 1] > 3):
249
p = r
250
q = w[r - 1]
251
if h1 == r:
252
h1 = h1 - 1
253
fixit = 1
254
else:
255
p = r
256
r = r - 1
257
q = 2
258
259
if p <= h1:
260
h1 = p - 1
261
if p <= r:
262
needr = 1
263
elif p <= h2:
264
needh2 = 1
265
elif l[h2 - 1] == l[h1 - 1] - 1 and n - h2 == r - h1:
266
if p <= c:
267
needc = 1
268
else:
269
c = INT_MAX
270
271
cdef int oldp = p
272
cdef int delta = q - p
273
cdef int oldlq = l[q - 1]
274
cdef int oldwq = w[q - 1]
275
p = INT_MAX
276
277
for i from oldp <= i <= n:
278
l[i - 1] = l[i - 1 + delta]
279
if l[i - 1] == 2:
280
w[i - 1] = 1
281
else:
282
p = i
283
if l[i - 1] == oldlq:
284
q = oldwq
285
else:
286
q = w[i - 1 + delta] - delta
287
w[i - 1] = q
288
if needr == 1 and l[i - 1] == 2:
289
needr = 0
290
needh2 = 1
291
r = i - 1
292
if needh2 == 1 and l[i - 1] <= l[i - 2] and i > r + 1:
293
needh2 = 0
294
h2 = i - 1
295
if l[h2 - 1] == l[h1 - 1] - 1 and n - h2 == r - h1:
296
needc = 1
297
else:
298
c = INT_MAX
299
if needc == 1:
300
if l[i - 1] != l[h1 - h2 + i - 1] - 1:
301
needc = 0
302
c = i
303
else:
304
c = i + 1
305
306
if fixit == 1:
307
r = n - h1 + 1
308
for i from r < i <= n:
309
l[i - 1] = i - r + 1
310
w[i - 1] = i - 1
311
w[r] = 1
312
h2 = n
313
p = n
314
q = p - 1
315
c = INT_MAX
316
else:
317
if p == INT_MAX:
318
if l[oldp - 2] != 2:
319
p = oldp - 1
320
else:
321
p = oldp - 2
322
q = w[p - 1]
323
if needh2 == 1:
324
h2 = n
325
if l[h2 - 1] == l[h1 - 1] - 1 and h1 == r:
326
c = n + 1
327
else:
328
c = INT_MAX
329
330
self.p = p
331
self.q = q
332
self.h1 = h1
333
self.h2 = h2
334
self.c = c
335
self.r = r
336
self.l = l
337
self.current_level_sequence = w
338
339
return 0
340
341