Repository: networkx/networkx

Issue:
inter_community_non_edges ignore directionality
Hi,

I think the function:

nx.algorithms.community.quality.inter_community_non_edges()

does not work properly for directed graph. It always return the non-edge of a undirected graph, basically halving the number of edges. This mean that the performance function (nx.algorithms.community.performance) will never by higher than 50% for a directed graph.

I'm using version '2.0.dev_20170801111157', python 3.5.1

Best,

Nicolas 


Discussion:
Can you provide a short example to demonstrate this?
I will be helpful to know more precisely what the trouble is.
Thanks!
Hi,
In the example below, you will find that the number of intra_community_edges is multiplied by two when the graph is transform in a directed one, but the number of inter-community non-edge do not change. I found this bug using real life data imported from panda dataframes.

Thanks!

Nicolas

import networkx as nx
G = nx.random_partition_graph([10,10,10],.25,.01, seed=12345)

partition = G.graph['partition']
perf = nx.algorithms.community.performance(G,partition )
intra_edges = nx.algorithms.community.quality.intra_community_edges(G, partition)
inter_edges = nx.algorithms.community.quality.inter_community_non_edges(G, partition)
print('undirected')
print(perf)
print(intra_edges)
print(inter_edges)


G2 = G.to_directed()
partition = G2.graph['partition']
perf = nx.algorithms.community.performance(G2,partition )
intra_edges = nx.algorithms.community.quality.intra_community_edges(G2, partition)
inter_edges = nx.algorithms.community.quality.inter_community_non_edges(G2, partition)
print('directed')
print(perf)
print(intra_edges)
print(inter_edges)   

Resolving patch:
diff --git a/networkx/algorithms/community/quality.py b/networkx/algorithms/community/quality.py
--- a/networkx/algorithms/community/quality.py
+++ b/networkx/algorithms/community/quality.py
@@ -114,7 +114,10 @@ def inter_community_edges(G, partition):
     #                                    for block in partition))
     #     return sum(1 for u, v in G.edges() if aff[u] != aff[v])
     #
-    return nx.quotient_graph(G, partition, create_using=nx.MultiGraph()).size()
+    if G.is_directed():
+        return nx.quotient_graph(G, partition, create_using=nx.MultiDiGraph()).size()
+    else:
+        return nx.quotient_graph(G, partition, create_using=nx.MultiGraph()).size()
 
 
 def inter_community_non_edges(G, partition):


Test patch:
diff --git a/networkx/algorithms/community/tests/test_quality.py b/networkx/algorithms/community/tests/test_quality.py
--- a/networkx/algorithms/community/tests/test_quality.py
+++ b/networkx/algorithms/community/tests/test_quality.py
@@ -12,6 +12,7 @@
 """
 from __future__ import division
 
+from nose.tools import assert_equal
 from nose.tools import assert_almost_equal
 
 import networkx as nx
@@ -19,6 +20,7 @@
 from networkx.algorithms.community import coverage
 from networkx.algorithms.community import modularity
 from networkx.algorithms.community import performance
+from networkx.algorithms.community.quality import inter_community_edges
 
 
 class TestPerformance(object):
@@ -61,3 +63,17 @@ def test_modularity():
     assert_almost_equal(-16 / (14 ** 2), modularity(G, C))
     C = [{0, 1, 2}, {3, 4, 5}]
     assert_almost_equal((35 * 2) / (14 ** 2), modularity(G, C))
+
+
+def test_inter_community_edges_with_digraphs():
+    G = nx.complete_graph(2, create_using = nx.DiGraph())
+    partition = [{0}, {1}]
+    assert_equal(inter_community_edges(G, partition), 2)
+
+    G = nx.complete_graph(10, create_using = nx.DiGraph())
+    partition = [{0}, {1, 2}, {3, 4, 5}, {6, 7, 8, 9}]
+    assert_equal(inter_community_edges(G, partition), 70)
+
+    G = nx.cycle_graph(4, create_using = nx.DiGraph())
+    partition = [{0, 1}, {2, 3}]
+    assert_equal(inter_community_edges(G, partition), 2)