Path: blob/master/sage/graphs/graph_decompositions/rankwidth.pyx
4069 views
r"""1Rank Decompositions of graphs23This modules wraps a C code from Philipp Klaus Krause computing a an optimal4rank-decomposition [RWKlause]_.56**Definitions :**78Given a graph `G` and a subset `S\subseteq V(G)` of vertices, the *rank-width*9of `S` in `G`, denoted `rw_G(S)`, is equal to the rank in `GF(2)` of the `|S|10\times (|V|-|S|)` matrix of the adjacencies between the vertices of `S` and11`V\backslash S`. By definition, `rw_G(S)` is qual to `rw_G(\overline S)` where12`\overline S` is the complement of `S` in `V(G)`.1314A *rank-decomposition* of `G` is a tree whose `n` leaves are the elements of15`V(G)`, and whose internal noes have degree 3. In a tree, ay edge naturally16corresponds to a bipartition of the vertex set : indeed, the reoal of any edge17splits the tree into two connected components, thus splitting the set of leaves18(i.e. vertices of `G`) into two sets. Hence we can define for any edge `e\in19E(G)` a width equal to the value `rw_G(S)` or `rw_G(\overline S)`, where20`S,\overline S` is the bipartition obtained from `e`. The *rank-width*21associated to the whole decomposition is then set to the maximum of the width of22all the edges it contains.2324A *rank-decomposition* is said to be optimal for `G` if it is the decomposition25achieving the minimal *rank-width*.2627**RW -- The original source code :**2829RW [RWKlause]_ is a program that calculates rank-width and30rank-decompositions. It is based on ideas from :3132* "Computing rank-width exactly" by Sang-il Oum [Oum]_33* "Sopra una formula numerica" by Ernesto Pascal34* "Generation of a Vector from the Lexicographical Index" by B.P. Buckles and M. Lybanon [BL]_35* "Fast additions on masked integers" by Michael D. Adams and David S. Wise [AW]_3637**OUTPUT:**3839The rank decomposition is returned as a tree whose vertices are subsets of40`V(G)`. Its leaves, corresponding to the vertices of `G` are sets of 1 elements,41i.e. singletons.4243::4445sage: g = graphs.PetersenGraph()46sage: rw, tree = g.rank_decomposition()47sage: all(len(v)==1 for v in tree if tree.degree(v) == 1)48True4950The internal nodes are sets of the decomposition. This way, it is easy to deduce51the bipartition associated to an edge from the tree. Indeed, two adjacent52vertices of the tree are comarable sets : they yield the bipartition obtained53from the smaller of the two and its complement.5455::5657sage: g = graphs.PetersenGraph()58sage: rw, tree = g.rank_decomposition()59sage: u = Set([8, 9, 3, 7])60sage: v = Set([8, 9])61sage: tree.has_edge(u,v)62True63sage: m = min(u,v)64sage: bipartition = (m, Set(g.vertices()) - m)65sage: bipartition66({8, 9}, {0, 1, 2, 3, 4, 5, 6, 7})6768.. WARNING::6970* The current implementation cannot handle graphs of `\geq 32` vertices.7172* A bug that has been reported upstream make the code crash immediately on73instances of size `30`. If you experience this kind of bug please report74it to us, what we need is some information on the hardware you run to know75where it comes from !7677EXAMPLE::7879sage: g = graphs.PetersenGraph()80sage: g.rank_decomposition()81(3, Graph on 19 vertices)8283AUTHORS:8485- Philipp Klaus Krause : Implementation of the C algorithm [RWKlause]_.86- Nathann Cohen : Interface with Sage and documentation.8788REFERENCES:8990.. [RWKlause] Philipp Klaus Krause -- rw v0.291http://pholia.tdi.informatik.uni-frankfurt.de/~philipp/software/rw.shtml9293.. [Oum] Sang-il Oum94Computing rank-width exactly95Information Processing Letters, 200896vol. 109, n. 13, p. 745--74897Elsevier98http://mathsci.kaist.ac.kr/~sangil/pdf/2008exp.pdf99100.. [BL] Buckles, B.P. and Lybanon, M.101Algorithm 515: generation of a vector from the lexicographical index102ACM Transactions on Mathematical Software (TOMS), 1977103vol. 3, n. 2, pages 180--182104ACM105106.. [AW] Adams, M.D. and Wise, D.S.107Fast additions on masked integers108ACM SIGPLAN Notices, 2006109vol. 41, n.5, pages 39--45110ACM111http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.1801&rep=rep1&type=pdf112113Methods114-------115"""116117#*****************************************************************************118# Copyright (C) 2011 Nathann Cohen <[email protected]>119#120# Distributed under the terms of the GNU General Public License (GPL)121# http://www.gnu.org/licenses/122#*****************************************************************************123124125include '../../ext/stdsage.pxi'126include '../../misc/bitset_pxd.pxi'127include "../../ext/interrupt.pxi"128129cdef list id_to_vertices130cdef dict vertices_to_id131132def rank_decomposition(G, verbose = False):133r"""134Computes an optimal rank-decomposition of the given graph.135136This function is available as a method of the :class:`Graph137<sage.graphs.graph>` class. See :meth:`rank_decomposition138<sage.graphs.graph.Graph.rank_decomposition>`.139140INPUT:141142- ``verbose`` (boolean) -- whether to display progress information while143computing the decomposition.144145OUTPUT:146147A pair ``(rankwidth, decomposition_tree)``, where ``rankwidth`` is a148numerical value and ``decomposition_tree`` is a ternary tree describing the149decomposition (cf. the module's documentation).150151EXAMPLE::152153sage: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition154sage: g = graphs.PetersenGraph()155sage: rank_decomposition(g)156(3, Graph on 19 vertices)157158On more than 32 vertices::159160sage: g = graphs.RandomGNP(40, .5)161sage: rank_decomposition(g)162Traceback (most recent call last):163...164Exception: The rank decomposition cannot be computed on graphs of >= 32 vertices.165166The empty graph::167168sage: g = Graph()169sage: rank_decomposition(g)170(0, Graph on 0 vertices)171"""172cdef int n = G.order()173174if n >= 32:175raise Exception("The rank decomposition cannot be computed "+176"on graphs of >= 32 vertices.")177178elif n == 0:179from sage.graphs.graph import Graph180return (0, Graph())181182global num_vertices183184cdef int i185186if sage_graph_to_matrix(G):187raise Exception("There has been a mistake while converting the Sage "+188"graph to a C structure. The memory is probably "+189"insufficient (2^(n+1) is a *LOT*).")190191for 0 <= i < n+1:192193if verbose:194print "Calculating for subsets of size ", i, "/",(n+1)195196# We want to properly deal with exceptions, in particular197# KeyboardInterrupt. Whatever happens, when this code fails the memory198# *HAS* to be freed, as it is particularly greedy (a graph of 29199# vertices already requires more than 1GB of memory).200201if not sig_on_no_except():202destroy_rw()203cython_check_exception()204205# Actual computation206calculate_level(i)207_sig_off208209cdef int rank_width = <int> get_rw()210211#Original way of displaying the decomposition212#print_rank_dec(0x7ffffffful >> (31 - num_vertices), 0)213g = mkgraph()214215# Free the memory216destroy_rw()217218return (rank_width, g)219220cdef int sage_graph_to_matrix(G):221r"""222Converts the given Sage graph as an adjacency matrix.223"""224global id_to_vertices225global vertices_to_id226global adjacency_matrix227global slots228global cslots229230id_to_vertices = []231vertices_to_id = {}232233global num_vertices234num_vertices = G.order()235236cdef int i,j237238# Prepares the C structure for the computation239if init_rw_dec(num_vertices):240# The original code does not completely frees the memory in case of241# error242if cslots != NULL:243sage_free(cslots)244if slots != NULL:245sage_free(slots)246if adjacency_matrix != NULL:247sage_free(adjacency_matrix)248return 1249250memset(adjacency_matrix, 0, sizeof(subset_t) * num_vertices)251252# Initializing the lists of vertices253for i,v in enumerate(G.vertices()):254id_to_vertices.append(v)255vertices_to_id[v] = i256257# Filling the matrix258for u,v in G.edges(labels = False):259if u==v:260continue261set_am(vertices_to_id[u], vertices_to_id[v], 1)262263# All is fine.264return 0265266cdef uint_fast32_t bitmask(int i):267return(1ul << i)268269cdef void set_am(int i, int j, int val):270r"""271Set/Unset an arc between vertices i and j272273(this function is a copy of what can be found in rankwidth/rw.c)274"""275global adjacency_matrix276277adjacency_matrix[i] &= ~bitmask(j)278adjacency_matrix[j] &= ~bitmask(i)279280if val:281adjacency_matrix[i] |= bitmask(j)282adjacency_matrix[j] |= bitmask(i)283284cdef void print_rank_dec(subset_t s, int l):285r"""286Prints the current rank decomposition as a text287288This function is a copy of the C routine printing the rank-decomposition is289the original source code. It s not used at the moment, but can still prove290useful when debugging the code.291"""292global cslots293294print ('\t'*l),295296print "cslot: ", <unsigned int> s297if cslots[s] == 0:298return299print_rank_dec(cslots[s], l + 1)300print_rank_dec(s & ~cslots[s], l + 1)301302def mkgraph():303r"""304Returns the graph corresponding the the current rank-decomposition.305306(This function is for internal use)307308EXAMPLE::309310sage: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition311sage: g = graphs.PetersenGraph()312sage: rank_decomposition(g)313(3, Graph on 19 vertices)314"""315global cslots316global num_vertices317global id_to_vertices318319cdef subset_t s320321from sage.graphs.graph import Graph322g = Graph()323324cdef subset_t * tab = <subset_t *> sage_malloc(sizeof(subset_t) * (2*num_vertices -1))325tab[0] = 0x7ffffffful >> (31 - num_vertices)326327cdef int beg = 0328cdef int end = 1329330while beg != end:331332s = tab[beg]333beg += 1334335if cslots[s] == 0:336continue337338g.add_edge(bitset_to_vertex_set(s), bitset_to_vertex_set(s&~cslots[s]))339g.add_edge(bitset_to_vertex_set(s), bitset_to_vertex_set(cslots[s]))340341tab[end] = s&~cslots[s]342end += 1343tab[end] = cslots[s]344end += 1345346sage_free(tab)347return g348349cdef bitset_to_vertex_set(subset_t s):350"""351Returns as a Set object the set corresponding to the given subset_t352variable.353"""354from sage.rings.integer import Integer355from sage.sets.set import Set356from sage.misc.bitset import FrozenBitset357return Set(list(FrozenBitset((Integer(<unsigned int> s).binary())[::-1])))358359360