# Ticket #13917: trac_13917.patch

File trac_13917.patch, 17.7 KB (added by ncohen, 8 years ago)
• ## doc/en/reference/graphs/index.rst

# HG changeset patch
# User Nathann Cohen <nathann.cohen@gmail.com>
# Date 1357313418 -3600
# Node ID c1208a86125e08b8f6e3e7a0d9f23e4329818118
# Parent  f8d13a70c806e4233a4d7927f1857a8cbf90af5f
IndependentSets class

diff --git a/doc/en/reference/graphs/index.rst b/doc/en/reference/graphs/index.rst
 a sage/graphs/graph_coloring sage/graphs/cliquer sage/graphs/independent_sets sage/graphs/comparability sage/graphs/line_graph sage/graphs/spanning_tree
• ## module_list.py

diff --git a/module_list.py b/module_list.py
 a sources = ['sage/graphs/cliquer.pyx'], libraries = ['cliquer']), Extension('sage.graphs.independent_sets', sources = ['sage/graphs/independent_sets.pyx']), Extension('sage.graphs.graph_decompositions.vertex_separation', sources = ['sage/graphs/graph_decompositions/vertex_separation.pyx']),
• ## sage/graphs/graph.py

diff --git a/sage/graphs/graph.py b/sage/graphs/graph.py
 a ### Cliques def cliques_maximal(self): """ Returns the list of all maximal cliques, with each clique represented by a list of vertices. A clique is an induced complete subgraph, and a maximal clique is one not contained in a larger one. .. NOTE:: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph. ALGORITHM: This function is based on NetworkX's implementation of the Bron and Kerbosch Algorithm [BroKer1973]_. - For graphs on >64 vertices this function uses NetworkX's implementation of the Bron and Kerbosch Algorithm [BroKer1973]_. - For small graphs, this function uses :mod:sage.graphs.independent_sets. REFERENCE: .. [BroKer1973] Coen Bron and Joep Kerbosch. (1973). Algorithm 457: Finding All Cliques of an Undirected Graph. Commun. ACM. v 16. n 9.  pages 575-577. ACM Press. [Online] Available: http://www.ram.org/computing/rambin/rambin.html EXAMPLES:: sage: graphs.ChvatalGraph().cliques_maximal() [[0, 1], [0, 4], [0, 6], [0, 9], [2, 1], [2, 3], [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [5, 1], [5, 4], [5, 10], [5, 11], [7, 1], [7, 8], [7, 11], [8, 4], [8, 10], [10, 6], [10, 9], [11, 6], [11, 9]] [[0, 1], [0, 4], [0, 6], [0, 9], [1, 2], [1, 5], [1, 7], [2, 3], [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10], [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]] sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) sage: G.show(figsize=[2,2]) sage: G.cliques_maximal() [[0, 1, 2], [0, 1, 3]] sage: C=graphs.PetersenGraph() sage: C.cliques_maximal() [[0, 1], [0, 4], [0, 5], [2, 1], [2, 3], [2, 7], [3, 4], [3, 8], [6, 1], [6, 8], [6, 9], [7, 5], [7, 9], [8, 5], [9, 4]] [[0, 1], [0, 4], [0, 5], [1, 2], [1, 6], [2, 3], [2, 7], [3, 4], [3, 8], [4, 9], [5, 7], [5, 8], [6, 8], [6, 9], [7, 9]] sage: C = Graph('DJ{') sage: C.cliques_maximal() [[4, 0], [4, 1, 2, 3]] [[0, 4], [1, 2, 3, 4]] """ import networkx return sorted(networkx.find_cliques(self.networkx_graph(copy=False))) if self.order() > 0 and self.order() <= 64: from sage.graphs.independent_sets import IndependentSets return sorted(IndependentSets(self, maximal = True, complement = True)) else: import networkx return sorted(networkx.find_cliques(self.networkx_graph(copy=False))) cliques = deprecated_function_alias(5739, cliques_maximal) {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: E = C.cliques_maximal() sage: E [[4, 0], [4, 1, 2, 3]] [[0, 4], [1, 2, 3, 4]] sage: C.cliques_number_of(cliques=E) {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: F = graphs.Grid2dGraph(2,3) {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} sage: E = C.cliques_maximal() sage: E [[4, 0], [4, 1, 2, 3]] [[0, 4], [1, 2, 3, 4]] sage: C.cliques_vertex_clique_number(cliques=E,algorithm="networkx") {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} sage: F = graphs.Grid2dGraph(2,3) {0: [[4, 0]], 1: [[4, 1, 2, 3]], 2: [[4, 1, 2, 3]], 3: [[4, 1, 2, 3]], 4: [[4, 0], [4, 1, 2, 3]]} sage: E = C.cliques_maximal() sage: E [[4, 0], [4, 1, 2, 3]] [[0, 4], [1, 2, 3, 4]] sage: C.cliques_containing_vertex(cliques=E) {0: [[4, 0]], 1: [[4, 1, 2, 3]], 2: [[4, 1, 2, 3]], 3: [[4, 1, 2, 3]], 4: [[4, 0], [4, 1, 2, 3]]} {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], 3: [[1, 2, 3, 4]], 4: [[0, 4], [1, 2, 3, 4]]} sage: F = graphs.Grid2dGraph(2,3) sage: X = F.cliques_containing_vertex() sage: for v in sorted(X.iterkeys()): """ Returns the clique complex of self. This is the largest simplicial complex on the vertices of self whose 1-skeleton is self. This is only makes sense for undirected simple graphs. EXAMPLES:: sage: g = Graph({0:[1,2],1:[2],4:[]}) sage: g.clique_complex() Simplicial complex with vertex set (0, 1, 2, 4) and facets {(4,), (0, 1, 2)} sage: h = Graph({0:[1,2,3,4],1:[2,3,4],2:[3]}) sage: x = h.clique_complex() sage: x
• ## new file sage/graphs/independent_sets.pxd

diff --git a/sage/graphs/independent_sets.pxd b/sage/graphs/independent_sets.pxd
new file mode 100644
 - from libc.stdint cimport uint32_t, uint64_t cdef class IndependentSets: cdef uint64_t count cdef uint64_t[64] g cdef list vertices cdef dict vertex_to_int cdef int n cdef int i cdef int count_only cdef uint64_t one cdef uint64_t current_set cdef int maximal
• ## new file sage/graphs/independent_sets.pyx

diff --git a/sage/graphs/independent_sets.pyx b/sage/graphs/independent_sets.pyx
new file mode 100644
 - r""" Independent sets This module implements the :class:IndependentSets class which can be used to : - List the independent sets of a graph - Count them (which is obviously faster) - Test whether a set of vertices is an independent set It can also be restricted to focus on (inclusionwise) maximal independent sets. See the documentation of :class:IndependentSets for actual examples. Classes and methods ------------------- """ cdef inline int isin(uint64_t s,int i): return (s>>i)&1 cdef inline int ismaximal(uint64_t[64] g, int n, uint64_t s): cdef int i for i in range(n): if (not isin(s,i)) and ((g[i]&s) == 0): return False return True cdef class IndependentSets: r""" An instance of this class represents the set of independent sets of a graph. INPUT: - G -- a graph - maximal (boolean) -- whether to only consider (inclusionwise) maximal independent sets. Set to False by default. - complement (boolean) -- whether to consider the graph's complement (i.e. cliques instead of independent sets). Set to False by default. .. WARNING:: - This implementation can only handle graphs with \leq 64 vertices. EXAMPLES: Listing all independent sets of the Claw graph:: sage: from sage.graphs.independent_sets import IndependentSets sage: g = graphs.ClawGraph() sage: list(IndependentSets(g)) [[0], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3], []] Count them:: sage: IndependentSets(g).cardinality() 9 List only the maximal independent sets:: sage: list(IndependentSets(g, maximal = True)) [[0], [1, 2, 3]] And count them:: sage: IndependentSets(g, maximal = True).cardinality() 2 """ def __init__(self, G, maximal = False, complement = False): r""" Constructor for this class TESTS:: sage: from sage.graphs.independent_sets import IndependentSets sage: IndependentSets(graphs.PetersenGraph()) 64 or G.order() == 0: raise ValueError("This class can only handle non-empty graphs of size at most 64") # Map from Vertex to Integer, and from Integer to Vertex self.vertex_to_int = {v:id for id,v in enumerate(G.vertices())} self.vertices = G.vertices() self.n = G.order() self.maximal = maximal # 1<<32 is not a good idea, as it is equal to 1. one << 32 is not, though. self.one = 1 # A local copy of the graph on 64-bits integers for i in range(self.n): self.g[i] = 0 for u,v in G.edges(labels = False): u = self.vertex_to_int[u] v = self.vertex_to_int[v] self.g[u] |= (self.one<i are zero. while True: # If i is in current_set if isin(self.current_set,self.i): # We have found an independent set ! if(self.g[self.i]&self.current_set) == 0: # Saving that set tmp = self.current_set # Preparing for the next set, except if we set the last bit. if self.i < self.n-1: # Adding (i+1)th bit self.current_set |= self.one<<(self.i+1) self.i += 1 else: self.current_set &= ~(self.one<<(self.i)) # Returning the result if necessary ... if self.maximal and not ismaximal(self.g,self.n, tmp): continue self.count += 1 if not self.count_only: return [self.vertices[j] for j in range(self.i+1) if isin(tmp,j)] else: # Removing the ith bit self.current_set &= ~(self.one<>(63-j))&1), print ""