Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/graph_decompositions/rankwidth.pyx
4069 views
1
r"""
2
Rank Decompositions of graphs
3
4
This modules wraps a C code from Philipp Klaus Krause computing a an optimal
5
rank-decomposition [RWKlause]_.
6
7
**Definitions :**
8
9
Given a graph `G` and a subset `S\subseteq V(G)` of vertices, the *rank-width*
10
of `S` in `G`, denoted `rw_G(S)`, is equal to the rank in `GF(2)` of the `|S|
11
\times (|V|-|S|)` matrix of the adjacencies between the vertices of `S` and
12
`V\backslash S`. By definition, `rw_G(S)` is qual to `rw_G(\overline S)` where
13
`\overline S` is the complement of `S` in `V(G)`.
14
15
A *rank-decomposition* of `G` is a tree whose `n` leaves are the elements of
16
`V(G)`, and whose internal noes have degree 3. In a tree, ay edge naturally
17
corresponds to a bipartition of the vertex set : indeed, the reoal of any edge
18
splits the tree into two connected components, thus splitting the set of leaves
19
(i.e. vertices of `G`) into two sets. Hence we can define for any edge `e\in
20
E(G)` a width equal to the value `rw_G(S)` or `rw_G(\overline S)`, where
21
`S,\overline S` is the bipartition obtained from `e`. The *rank-width*
22
associated to the whole decomposition is then set to the maximum of the width of
23
all the edges it contains.
24
25
A *rank-decomposition* is said to be optimal for `G` if it is the decomposition
26
achieving the minimal *rank-width*.
27
28
**RW -- The original source code :**
29
30
RW [RWKlause]_ is a program that calculates rank-width and
31
rank-decompositions. It is based on ideas from :
32
33
* "Computing rank-width exactly" by Sang-il Oum [Oum]_
34
* "Sopra una formula numerica" by Ernesto Pascal
35
* "Generation of a Vector from the Lexicographical Index" by B.P. Buckles and M. Lybanon [BL]_
36
* "Fast additions on masked integers" by Michael D. Adams and David S. Wise [AW]_
37
38
**OUTPUT:**
39
40
The rank decomposition is returned as a tree whose vertices are subsets of
41
`V(G)`. Its leaves, corresponding to the vertices of `G` are sets of 1 elements,
42
i.e. singletons.
43
44
::
45
46
sage: g = graphs.PetersenGraph()
47
sage: rw, tree = g.rank_decomposition()
48
sage: all(len(v)==1 for v in tree if tree.degree(v) == 1)
49
True
50
51
The internal nodes are sets of the decomposition. This way, it is easy to deduce
52
the bipartition associated to an edge from the tree. Indeed, two adjacent
53
vertices of the tree are comarable sets : they yield the bipartition obtained
54
from the smaller of the two and its complement.
55
56
::
57
58
sage: g = graphs.PetersenGraph()
59
sage: rw, tree = g.rank_decomposition()
60
sage: u = Set([8, 9, 3, 7])
61
sage: v = Set([8, 9])
62
sage: tree.has_edge(u,v)
63
True
64
sage: m = min(u,v)
65
sage: bipartition = (m, Set(g.vertices()) - m)
66
sage: bipartition
67
({8, 9}, {0, 1, 2, 3, 4, 5, 6, 7})
68
69
.. WARNING::
70
71
* The current implementation cannot handle graphs of `\geq 32` vertices.
72
73
* A bug that has been reported upstream make the code crash immediately on
74
instances of size `30`. If you experience this kind of bug please report
75
it to us, what we need is some information on the hardware you run to know
76
where it comes from !
77
78
EXAMPLE::
79
80
sage: g = graphs.PetersenGraph()
81
sage: g.rank_decomposition()
82
(3, Graph on 19 vertices)
83
84
AUTHORS:
85
86
- Philipp Klaus Krause : Implementation of the C algorithm [RWKlause]_.
87
- Nathann Cohen : Interface with Sage and documentation.
88
89
REFERENCES:
90
91
.. [RWKlause] Philipp Klaus Krause -- rw v0.2
92
http://pholia.tdi.informatik.uni-frankfurt.de/~philipp/software/rw.shtml
93
94
.. [Oum] Sang-il Oum
95
Computing rank-width exactly
96
Information Processing Letters, 2008
97
vol. 109, n. 13, p. 745--748
98
Elsevier
99
http://mathsci.kaist.ac.kr/~sangil/pdf/2008exp.pdf
100
101
.. [BL] Buckles, B.P. and Lybanon, M.
102
Algorithm 515: generation of a vector from the lexicographical index
103
ACM Transactions on Mathematical Software (TOMS), 1977
104
vol. 3, n. 2, pages 180--182
105
ACM
106
107
.. [AW] Adams, M.D. and Wise, D.S.
108
Fast additions on masked integers
109
ACM SIGPLAN Notices, 2006
110
vol. 41, n.5, pages 39--45
111
ACM
112
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.1801&rep=rep1&type=pdf
113
114
Methods
115
-------
116
"""
117
118
#*****************************************************************************
119
# Copyright (C) 2011 Nathann Cohen <[email protected]>
120
#
121
# Distributed under the terms of the GNU General Public License (GPL)
122
# http://www.gnu.org/licenses/
123
#*****************************************************************************
124
125
126
include '../../ext/stdsage.pxi'
127
include '../../misc/bitset_pxd.pxi'
128
include "../../ext/interrupt.pxi"
129
130
cdef list id_to_vertices
131
cdef dict vertices_to_id
132
133
def rank_decomposition(G, verbose = False):
134
r"""
135
Computes an optimal rank-decomposition of the given graph.
136
137
This function is available as a method of the :class:`Graph
138
<sage.graphs.graph>` class. See :meth:`rank_decomposition
139
<sage.graphs.graph.Graph.rank_decomposition>`.
140
141
INPUT:
142
143
- ``verbose`` (boolean) -- whether to display progress information while
144
computing the decomposition.
145
146
OUTPUT:
147
148
A pair ``(rankwidth, decomposition_tree)``, where ``rankwidth`` is a
149
numerical value and ``decomposition_tree`` is a ternary tree describing the
150
decomposition (cf. the module's documentation).
151
152
EXAMPLE::
153
154
sage: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition
155
sage: g = graphs.PetersenGraph()
156
sage: rank_decomposition(g)
157
(3, Graph on 19 vertices)
158
159
On more than 32 vertices::
160
161
sage: g = graphs.RandomGNP(40, .5)
162
sage: rank_decomposition(g)
163
Traceback (most recent call last):
164
...
165
Exception: The rank decomposition cannot be computed on graphs of >= 32 vertices.
166
167
The empty graph::
168
169
sage: g = Graph()
170
sage: rank_decomposition(g)
171
(0, Graph on 0 vertices)
172
"""
173
cdef int n = G.order()
174
175
if n >= 32:
176
raise Exception("The rank decomposition cannot be computed "+
177
"on graphs of >= 32 vertices.")
178
179
elif n == 0:
180
from sage.graphs.graph import Graph
181
return (0, Graph())
182
183
global num_vertices
184
185
cdef int i
186
187
if sage_graph_to_matrix(G):
188
raise Exception("There has been a mistake while converting the Sage "+
189
"graph to a C structure. The memory is probably "+
190
"insufficient (2^(n+1) is a *LOT*).")
191
192
for 0 <= i < n+1:
193
194
if verbose:
195
print "Calculating for subsets of size ", i, "/",(n+1)
196
197
# We want to properly deal with exceptions, in particular
198
# KeyboardInterrupt. Whatever happens, when this code fails the memory
199
# *HAS* to be freed, as it is particularly greedy (a graph of 29
200
# vertices already requires more than 1GB of memory).
201
202
if not sig_on_no_except():
203
destroy_rw()
204
cython_check_exception()
205
206
# Actual computation
207
calculate_level(i)
208
_sig_off
209
210
cdef int rank_width = <int> get_rw()
211
212
#Original way of displaying the decomposition
213
#print_rank_dec(0x7ffffffful >> (31 - num_vertices), 0)
214
g = mkgraph()
215
216
# Free the memory
217
destroy_rw()
218
219
return (rank_width, g)
220
221
cdef int sage_graph_to_matrix(G):
222
r"""
223
Converts the given Sage graph as an adjacency matrix.
224
"""
225
global id_to_vertices
226
global vertices_to_id
227
global adjacency_matrix
228
global slots
229
global cslots
230
231
id_to_vertices = []
232
vertices_to_id = {}
233
234
global num_vertices
235
num_vertices = G.order()
236
237
cdef int i,j
238
239
# Prepares the C structure for the computation
240
if init_rw_dec(num_vertices):
241
# The original code does not completely frees the memory in case of
242
# error
243
if cslots != NULL:
244
sage_free(cslots)
245
if slots != NULL:
246
sage_free(slots)
247
if adjacency_matrix != NULL:
248
sage_free(adjacency_matrix)
249
return 1
250
251
memset(adjacency_matrix, 0, sizeof(subset_t) * num_vertices)
252
253
# Initializing the lists of vertices
254
for i,v in enumerate(G.vertices()):
255
id_to_vertices.append(v)
256
vertices_to_id[v] = i
257
258
# Filling the matrix
259
for u,v in G.edges(labels = False):
260
if u==v:
261
continue
262
set_am(vertices_to_id[u], vertices_to_id[v], 1)
263
264
# All is fine.
265
return 0
266
267
cdef uint_fast32_t bitmask(int i):
268
return(1ul << i)
269
270
cdef void set_am(int i, int j, int val):
271
r"""
272
Set/Unset an arc between vertices i and j
273
274
(this function is a copy of what can be found in rankwidth/rw.c)
275
"""
276
global adjacency_matrix
277
278
adjacency_matrix[i] &= ~bitmask(j)
279
adjacency_matrix[j] &= ~bitmask(i)
280
281
if val:
282
adjacency_matrix[i] |= bitmask(j)
283
adjacency_matrix[j] |= bitmask(i)
284
285
cdef void print_rank_dec(subset_t s, int l):
286
r"""
287
Prints the current rank decomposition as a text
288
289
This function is a copy of the C routine printing the rank-decomposition is
290
the original source code. It s not used at the moment, but can still prove
291
useful when debugging the code.
292
"""
293
global cslots
294
295
print ('\t'*l),
296
297
print "cslot: ", <unsigned int> s
298
if cslots[s] == 0:
299
return
300
print_rank_dec(cslots[s], l + 1)
301
print_rank_dec(s & ~cslots[s], l + 1)
302
303
def mkgraph():
304
r"""
305
Returns the graph corresponding the the current rank-decomposition.
306
307
(This function is for internal use)
308
309
EXAMPLE::
310
311
sage: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition
312
sage: g = graphs.PetersenGraph()
313
sage: rank_decomposition(g)
314
(3, Graph on 19 vertices)
315
"""
316
global cslots
317
global num_vertices
318
global id_to_vertices
319
320
cdef subset_t s
321
322
from sage.graphs.graph import Graph
323
g = Graph()
324
325
cdef subset_t * tab = <subset_t *> sage_malloc(sizeof(subset_t) * (2*num_vertices -1))
326
tab[0] = 0x7ffffffful >> (31 - num_vertices)
327
328
cdef int beg = 0
329
cdef int end = 1
330
331
while beg != end:
332
333
s = tab[beg]
334
beg += 1
335
336
if cslots[s] == 0:
337
continue
338
339
g.add_edge(bitset_to_vertex_set(s), bitset_to_vertex_set(s&~cslots[s]))
340
g.add_edge(bitset_to_vertex_set(s), bitset_to_vertex_set(cslots[s]))
341
342
tab[end] = s&~cslots[s]
343
end += 1
344
tab[end] = cslots[s]
345
end += 1
346
347
sage_free(tab)
348
return g
349
350
cdef bitset_to_vertex_set(subset_t s):
351
"""
352
Returns as a Set object the set corresponding to the given subset_t
353
variable.
354
"""
355
from sage.rings.integer import Integer
356
from sage.sets.set import Set
357
from sage.misc.bitset import FrozenBitset
358
return Set(list(FrozenBitset((Integer(<unsigned int> s).binary())[::-1])))
359
360