161 lines
4.9 KiB
Python
161 lines
4.9 KiB
Python
import unittest
|
|
|
|
import easygraph as eg
|
|
|
|
|
|
def _get_cpp_module():
|
|
"""获取cpp_easygraph模块"""
|
|
try:
|
|
import cpp_easygraph
|
|
return cpp_easygraph
|
|
except ImportError:
|
|
return None
|
|
|
|
|
|
def _to_undirected_cpp(G_cpp_digraph):
|
|
"""将C++ DiGraph转换为C++ Graph无向图"""
|
|
import cpp_easygraph
|
|
|
|
G_cpp = cpp_easygraph.Graph()
|
|
G_cpp.graph.update(G_cpp_digraph.graph)
|
|
for node, node_attr in G_cpp_digraph.nodes.items():
|
|
G_cpp.add_node(node, **node_attr)
|
|
|
|
seen_edges = set()
|
|
for u, v, edge_data in G_cpp_digraph.edges:
|
|
edge = (min(u, v), max(u, v))
|
|
if edge not in seen_edges:
|
|
seen_edges.add(edge)
|
|
G_cpp.add_edge(u, v, **edge_data)
|
|
|
|
return G_cpp
|
|
|
|
|
|
def _communities_to_membership(G, communities):
|
|
|
|
if not isinstance(communities, list):
|
|
communities = list(communities)
|
|
|
|
N = G.number_of_nodes()
|
|
membership = [-1] * N
|
|
node_index = G.node_index
|
|
|
|
for comm_id, community in enumerate(communities):
|
|
for node in community:
|
|
if node in node_index:
|
|
node_id = node_index[node]
|
|
membership[node_id] = comm_id
|
|
|
|
return membership
|
|
|
|
|
|
class TestModularity(unittest.TestCase):
|
|
def setUp(self):
|
|
self.G = eg.Graph()
|
|
self.G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0)])
|
|
|
|
self.DG = eg.DiGraph()
|
|
self.DG.add_edges_from([(0, 1), (1, 2), (2, 0)])
|
|
|
|
self.G_weighted = eg.Graph()
|
|
self.G_weighted.add_edge(0, 1, weight=2)
|
|
self.G_weighted.add_edge(1, 2, weight=3)
|
|
self.G_weighted.add_edge(2, 0, weight=1)
|
|
|
|
self.G_selfloop = eg.Graph()
|
|
self.G_selfloop.add_edges_from([(0, 0), (1, 1), (0, 1)])
|
|
|
|
self.G_empty = eg.Graph()
|
|
|
|
self.config = type('Config', (), {
|
|
'is_directed': False
|
|
})()
|
|
|
|
def _get_cpp_module(self):
|
|
return _get_cpp_module()
|
|
|
|
def test_undirected_modularity(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
communities = [{0, 1}, {2, 3}]
|
|
membership = _communities_to_membership(self.G, communities)
|
|
q = cpeg.cpp_modularity(self.G.cpp(), membership)
|
|
self.assertIsInstance(q, float)
|
|
self.assertGreaterEqual(q, -1.0)
|
|
self.assertLessEqual(q, 1.0)
|
|
|
|
def test_directed_modularity(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
communities = [{0, 1, 2}]
|
|
membership = _communities_to_membership(self.DG, communities)
|
|
q = cpeg.cpp_modularity(self.DG.cpp(), membership)
|
|
self.assertIsInstance(q, float)
|
|
|
|
def test_weighted_graph(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
communities = [{0, 1}, {2}]
|
|
membership = _communities_to_membership(self.G_weighted, communities)
|
|
q = cpeg.cpp_modularity(self.G_weighted.cpp(), membership, weight="weight")
|
|
self.assertIsInstance(q, float)
|
|
|
|
def test_self_loops(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
communities = [{0, 1}]
|
|
membership = _communities_to_membership(self.G_selfloop, communities)
|
|
q = cpeg.cpp_modularity(self.G_selfloop.cpp(), membership)
|
|
self.assertIsInstance(q, float)
|
|
|
|
def test_single_community(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
communities = [{0, 1, 2, 3}]
|
|
membership = _communities_to_membership(self.G, communities)
|
|
q = cpeg.cpp_modularity(self.G.cpp(), membership)
|
|
self.assertIsInstance(q, float)
|
|
|
|
def test_each_node_its_own_community(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
communities = [{0}, {1}, {2}, {3}]
|
|
membership = _communities_to_membership(self.G, communities)
|
|
q = cpeg.cpp_modularity(self.G.cpp(), membership)
|
|
self.assertIsInstance(q, float)
|
|
|
|
def test_empty_community_list(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
q = cpeg.cpp_modularity(self.G.cpp(), [])
|
|
self.assertEqual(q, 0.0)
|
|
|
|
def test_python_cpp_consistency(self):
|
|
cpeg = self._get_cpp_module()
|
|
if cpeg is None:
|
|
self.skipTest("cpp_easygraph module not available")
|
|
|
|
communities_py = [{0, 1}, {2, 3}]
|
|
|
|
q_py = eg.functions.community.modularity(self.G, communities_py)
|
|
q_cpp = cpeg.cpp_modularity(self.G.cpp(), communities_py)
|
|
|
|
self.assertAlmostEqual(q_py, q_cpp, places=5)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main() |