Skip to content

Commit 12036b7

Browse files
committed
refactor: community_edge_betweenness() now always computes modularity
as weights represent connection strengths
1 parent e6479b1 commit 12036b7

File tree

3 files changed

+22
-21
lines changed

3 files changed

+22
-21
lines changed

src/_igraph/graphobject.c

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13076,7 +13076,7 @@ PyObject *igraphmodule_Graph_community_edge_betweenness(igraphmodule_GraphObject
1307613076
/* edge_betweenness = */ 0,
1307713077
/* merges = */ &merges,
1307813078
/* bridges = */ 0,
13079-
/* modularity = */ weights ? 0 : &q,
13079+
/* modularity = */ &q,
1308013080
/* membership = */ 0,
1308113081
PyObject_IsTrue(directed),
1308213082
weights,
@@ -13094,19 +13094,11 @@ PyObject *igraphmodule_Graph_community_edge_betweenness(igraphmodule_GraphObject
1309413094
igraph_vector_destroy(weights); free(weights);
1309513095
}
1309613096

13097-
if (weights == 0) {
13098-
/* Calculate modularity vector only in the unweighted case as we don't
13099-
* calculate modularities for the weighted case */
13100-
qs=igraphmodule_vector_t_to_PyList(&q, IGRAPHMODULE_TYPE_FLOAT);
13101-
igraph_vector_destroy(&q);
13102-
if (!qs) {
13103-
igraph_matrix_int_destroy(&merges);
13104-
return NULL;
13105-
}
13106-
} else {
13107-
qs = Py_None;
13108-
Py_INCREF(qs);
13109-
igraph_vector_destroy(&q);
13097+
qs = igraphmodule_vector_t_to_PyList(&q, IGRAPHMODULE_TYPE_FLOAT);
13098+
igraph_vector_destroy(&q);
13099+
if (!qs) {
13100+
igraph_matrix_int_destroy(&merges);
13101+
return NULL;
1311013102
}
1311113103

1311213104
ms=igraphmodule_matrix_int_t_to_PyList(&merges);
@@ -18531,12 +18523,18 @@ struct PyMethodDef igraphmodule_Graph_methods[] = {
1853118523
"is typically high. So we gradually remove the edge with the highest\n"
1853218524
"betweenness from the network and recalculate edge betweenness after every\n"
1853318525
"removal, as long as all edges are removed.\n\n"
18526+
"When edge weights are given, the ratio of betweenness and weight values\n"
18527+
"is used to choose which edges to remove first, as described in\n"
18528+
"M. E. J. Newman: Analysis of Weighted Networks (2004), Section C.\n"
18529+
"Thus, edges with large weights are treated as strong connections,\n"
18530+
"and will be removed later than weak connections having similar betweenness.\n"
18531+
"Weights are also used for calculating modularity.\n\n"
1853418532
"Attention: this function is wrapped in a more convenient syntax in the\n"
1853518533
"derived class L{Graph}. It is advised to use that instead of this version.\n\n"
1853618534
"@param directed: whether to take into account the directedness of the edges\n"
1853718535
" when we calculate the betweenness values.\n"
1853818536
"@param weights: name of an edge attribute or a list containing\n"
18539-
" edge weights.\n\n"
18537+
" edge weights. Higher weights indicate stronger connections.\n\n"
1854018538
"@return: a tuple with the merge matrix that describes the dendrogram\n"
1854118539
" and the modularity scores before each merge. The modularity scores\n"
1854218540
" use the weights if the original graph was weighted.\n"

src/igraph/community.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ def _community_edge_betweenness(graph, clusters=None, directed=True, weights=Non
235235
separate components. The result of the clustering will be represented
236236
by a dendrogram.
237237
238+
When edge weights are given, the ratio of betweenness and weight values
239+
is used to choose which edges to remove first, as described in
240+
M. E. J. Newman: Analysis of Weighted Networks (2004), Section C.
241+
Thus, edges with large weights are treated as strong connections,
242+
and will be removed later than weak connections having similar betweenness.
243+
Weights are also used for calculating modularity.
244+
238245
@param clusters: the number of clusters we would like to see. This
239246
practically defines the "level" where we "cut" the dendrogram to
240247
get the membership vector of the vertices. If C{None}, the dendrogram
@@ -245,7 +252,7 @@ def _community_edge_betweenness(graph, clusters=None, directed=True, weights=Non
245252
@param directed: whether the directionality of the edges should be
246253
taken into account or not.
247254
@param weights: name of an edge attribute or a list containing
248-
edge weights.
255+
edge weights. Higher weights indicate stronger connections.
249256
@return: a L{VertexDendrogram} object, initally cut at the maximum
250257
modularity or at the desired number of clusters.
251258
"""

tests/test_decomposition.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,7 @@ def testEdgeBetweenness(self):
263263
g.es["weight"] = 1
264264
g[0, 1] = g[1, 2] = g[2, 0] = g[3, 4] = 10
265265

266-
# We need to specify the desired cluster count explicitly; this is
267-
# because edge betweenness-based detection does not play well with
268-
# modularity-based cluster count selection (the edge weights have
269-
# different semantics) so we need to give igraph a hint
270-
cl = g.community_edge_betweenness(weights="weight").as_clustering(n=2)
266+
cl = g.community_edge_betweenness(weights="weight").as_clustering()
271267
self.assertMembershipsEqual(cl, [0, 0, 0, 1, 1])
272268
self.assertAlmostEqual(cl.q, 0.2750, places=3)
273269

0 commit comments

Comments
 (0)