From 0cf50a2ef56963f91d68a91ac281daced603d58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Fri, 28 Apr 2023 19:19:04 -0300 Subject: [PATCH 1/2] Support networkx 3.1 The functions `number_of_cliques()` and `cliques_containing_node()` are deprecated in networkx 3.1. This commit reimplements both functions based on method `cliques_maximal()`. --- src/sage/graphs/graph.py | 43 +++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index c2e42bcbd38..b6a10efbf48 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -6786,13 +6786,21 @@ def cliques_number_of(self, vertices=None, cliques=None): {(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2} sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) {(0, 1): 3, (1, 2): 2} + sage: F.cliques_number_of(vertices=(0, 1)) + 3 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) sage: G.show(figsize=[2,2]) sage: G.cliques_number_of() {0: 2, 1: 2, 2: 1, 3: 1} """ - import networkx - return networkx.number_of_cliques(self.networkx_graph(), vertices, cliques) + if cliques is None: + cliques = self.cliques_maximal() + + if vertices in self: # single vertex + return sum(1 for c in cliques if vertices in c) + else: + return { v : sum(1 for c in cliques if v in c) + for v in vertices or self } @doc_index("Clique-related methods") def cliques_get_max_clique_graph(self): @@ -7493,17 +7501,32 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): sage: C = Graph('DJ{') sage: C.cliques_containing_vertex() - {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: C.cliques_containing_vertex(4) + [[0, 4], [1, 2, 3, 4]] + sage: C.cliques_containing_vertex([0, 1]) + {0: [[0, 4]], 1: [[1, 2, 3, 4]]} sage: E = C.cliques_maximal() sage: E [[0, 4], [1, 2, 3, 4]] sage: C.cliques_containing_vertex(cliques=E) - {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]]} + {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: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) sage: G.show(figsize=[2,2]) sage: G.cliques_containing_vertex() - {0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], 3: [[0, 1, 3]]} + {0: [[0, 1, 2], [0, 1, 3]], + 1: [[0, 1, 2], [0, 1, 3]], + 2: [[0, 1, 2]], + 3: [[0, 1, 3]]} Since each clique of a 2 dimensional grid corresponds to an edge, the number of cliques in which a vertex is involved equals its degree:: @@ -7518,8 +7541,14 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): sage: sorted(sorted(x for x in L) for L in d[(0, 1)]) [[(0, 0), (0, 1)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]] """ - import networkx - return networkx.cliques_containing_node(self.networkx_graph(), vertices, cliques) + if cliques is None: + cliques = self.cliques_maximal() + + if vertices in self: # single vertex + return [c for c in cliques if vertices in c] + else: + return { v : [c for c in cliques if v in c] + for v in vertices or self } @doc_index("Clique-related methods") def clique_complex(self): From e599562cf5fdfb9799a5412fac40c2f8e9f97341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Thu, 4 May 2023 22:24:33 -0300 Subject: [PATCH 2/2] Improve `cliques_number_of()` and `cliques_containing_vertices()` The previous implementation was taken from the ones that are deprecated in networkx 3.1. We replace it by a better implementation suggested by David Coudert. --- src/sage/graphs/graph.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index b6a10efbf48..0d13f071dc4 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -6796,11 +6796,16 @@ def cliques_number_of(self, vertices=None, cliques=None): if cliques is None: cliques = self.cliques_maximal() - if vertices in self: # single vertex + if vertices in self: # single vertex return sum(1 for c in cliques if vertices in c) - else: - return { v : sum(1 for c in cliques if v in c) - for v in vertices or self } + + from collections import Counter + count = Counter() + + for c in cliques: + count.update(c) + + return {v : count[v] for v in vertices or self} @doc_index("Clique-related methods") def cliques_get_max_clique_graph(self): @@ -7544,11 +7549,17 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): if cliques is None: cliques = self.cliques_maximal() - if vertices in self: # single vertex + if vertices in self: # single vertex return [c for c in cliques if vertices in c] - else: - return { v : [c for c in cliques if v in c] - for v in vertices or self } + + from collections import defaultdict + d = defaultdict(list) + + for c in cliques: + for v in c: + d[v].append(c) + + return {v : d[v] for v in vertices or self} @doc_index("Clique-related methods") def clique_complex(self):