Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/trees.pyx
4057 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 "../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
if self.current_level_sequence != NULL:
89
sage_free(self.current_level_sequence)
90
91
def __str__(self):
92
r"""
93
EXAMPLES::
94
95
sage: from sage.graphs.trees import TreeIterator
96
sage: t = TreeIterator(100)
97
sage: print t # indirect doctest
98
Iterator over all trees with 100 vertices
99
"""
100
return "Iterator over all trees with %s vertices"%(self.vertices)
101
102
def __iter__(self):
103
r"""
104
Returns an iterator over all the trees with `n` vertices.
105
106
EXAMPLES::
107
108
sage: from sage.graphs.trees import TreeIterator
109
sage: t = TreeIterator(4)
110
sage: list(iter(t))
111
[Graph on 4 vertices, Graph on 4 vertices]
112
"""
113
return self
114
115
def __next__(self):
116
r"""
117
Returns the next tree with `n` vertices
118
119
EXAMPLES::
120
121
sage: from sage.graphs.trees import TreeIterator
122
sage: T = TreeIterator(5)
123
sage: [t for t in T] # indirect doctest
124
[Graph on 5 vertices, Graph on 5 vertices, Graph on 5 vertices]
125
"""
126
127
if not self.first_time and self.q == 0:
128
raise StopIteration
129
130
if self.first_time == 1:
131
self.l = <int *>sage_malloc(self.vertices * sizeof(int))
132
self.current_level_sequence = <int *>sage_malloc(self.vertices * sizeof(int))
133
134
if self.l == NULL or self.current_level_sequence == NULL:
135
raise MemoryError
136
137
self.generate_first_level_sequence()
138
self.first_time = 0
139
else:
140
self.generate_next_level_sequence()
141
142
cdef int i
143
cdef int vertex1
144
cdef int vertex2
145
cdef object G
146
147
# from networkx import MultiGraph
148
# G = Graph(self.vertices)
149
# cdef object XG = G._backend._nxg
150
#
151
# for i from 2 <= i <= self.vertices:
152
# vertex1 = i - 1
153
# vertex2 = self.current_level_sequence[i - 1] - 1
154
# XG.add_edge(vertex1, vertex2)
155
#
156
# return G
157
158
# Currently, c_graph does not have all the same functionality as networkx.
159
# Until it does, we can't generate graphs using the c_graph backend even
160
# though it is twice as fast (for our purposes) as networkx.
161
162
G = Graph(self.vertices, implementation='c_graph', sparse=True)
163
cdef SparseGraph SG = <SparseGraph> G._backend._cg
164
165
for i from 2 <= i <= self.vertices:
166
vertex1 = i - 1
167
vertex2 = self.current_level_sequence[i - 1] - 1
168
SG.add_arc_unsafe(vertex1, vertex2)
169
SG.add_arc_unsafe(vertex2, vertex1)
170
171
return G
172
173
cdef int generate_first_level_sequence(self):
174
r"""
175
Generates the level sequence representing the first tree with `n` vertices
176
"""
177
cdef int i
178
cdef int k
179
180
k = (self.vertices / 2) + 1
181
182
if self.vertices == 4:
183
self.p = 3
184
else:
185
self.p = self.vertices
186
self.q = self.vertices - 1
187
self.h1 = k
188
self.h2 = self.vertices
189
if self.vertices % 2 == 0:
190
self.c = self.vertices + 1
191
else:
192
self.c = INT_MAX # oo
193
194
self.r = k
195
196
for i from 1 <= i <= k:
197
self.l[i - 1] = i
198
for i from k < i <= self.vertices:
199
self.l[i - 1] = i - k + 1
200
for i from 0 <= i < self.vertices:
201
self.current_level_sequence[i] = i
202
if self.vertices > 2:
203
self.current_level_sequence[k] = 1
204
if self.vertices <= 3:
205
self.q = 0
206
207
return 0
208
209
cdef int generate_next_level_sequence(self):
210
r"""
211
Generates the level sequence representing the next tree with `n` vertices
212
"""
213
cdef int i
214
cdef int fixit = 0
215
216
cdef int needr = 0
217
cdef int needc = 0
218
cdef int needh2 = 0
219
220
cdef int n = self.vertices
221
cdef int p = self.p
222
cdef int q = self.q
223
cdef int h1 = self.h1
224
cdef int h2 = self.h2
225
cdef int c = self.c
226
cdef int r = self.r
227
cdef int *l = self.l
228
cdef int *w = self.current_level_sequence
229
230
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):
231
if (l[r - 1] > 3):
232
p = r
233
q = w[r - 1]
234
if h1 == r:
235
h1 = h1 - 1
236
fixit = 1
237
else:
238
p = r
239
r = r - 1
240
q = 2
241
242
if p <= h1:
243
h1 = p - 1
244
if p <= r:
245
needr = 1
246
elif p <= h2:
247
needh2 = 1
248
elif l[h2 - 1] == l[h1 - 1] - 1 and n - h2 == r - h1:
249
if p <= c:
250
needc = 1
251
else:
252
c = INT_MAX
253
254
cdef int oldp = p
255
cdef int delta = q - p
256
cdef int oldlq = l[q - 1]
257
cdef int oldwq = w[q - 1]
258
p = INT_MAX
259
260
for i from oldp <= i <= n:
261
l[i - 1] = l[i - 1 + delta]
262
if l[i - 1] == 2:
263
w[i - 1] = 1
264
else:
265
p = i
266
if l[i - 1] == oldlq:
267
q = oldwq
268
else:
269
q = w[i - 1 + delta] - delta
270
w[i - 1] = q
271
if needr == 1 and l[i - 1] == 2:
272
needr = 0
273
needh2 = 1
274
r = i - 1
275
if needh2 == 1 and l[i - 1] <= l[i - 2] and i > r + 1:
276
needh2 = 0
277
h2 = i - 1
278
if l[h2 - 1] == l[h1 - 1] - 1 and n - h2 == r - h1:
279
needc = 1
280
else:
281
c = INT_MAX
282
if needc == 1:
283
if l[i - 1] != l[h1 - h2 + i - 1] - 1:
284
needc = 0
285
c = i
286
else:
287
c = i + 1
288
289
if fixit == 1:
290
r = n - h1 + 1
291
for i from r < i <= n:
292
l[i - 1] = i - r + 1
293
w[i - 1] = i - 1
294
w[r] = 1
295
h2 = n
296
p = n
297
q = p - 1
298
c = INT_MAX
299
else:
300
if p == INT_MAX:
301
if l[oldp - 2] != 2:
302
p = oldp - 1
303
else:
304
p = oldp - 2
305
q = w[p - 1]
306
if needh2 == 1:
307
h2 = n
308
if l[h2 - 1] == l[h1 - 1] - 1 and h1 == r:
309
c = n + 1
310
else:
311
c = INT_MAX
312
313
self.p = p
314
self.q = q
315
self.h1 = h1
316
self.h2 = h2
317
self.c = c
318
self.r = r
319
self.l = l
320
self.current_level_sequence = w
321
322
return 0
323
324