Fix bug in modularity calculation
Summary: This diff does not fix our Louvain implementation completely. The algorithm internally still optimzies the wrong function, but this will at least correctly calculate the modularity value at the end. Fix of the algorithm will come in a separate diff Reviewers: dsantl Reviewed By: dsantl Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2603
This commit is contained in:
parent
0c111d52dc
commit
ec67e71d39
@ -78,14 +78,23 @@ double Graph::Modularity() const {
|
||||
if (total_w_ == 0)
|
||||
return 0;
|
||||
|
||||
std::unordered_map<uint32_t, double> weight_c;
|
||||
std::unordered_map<uint32_t, double> degree_c;
|
||||
|
||||
for (uint32_t i = 0; i < n_nodes_; ++i) {
|
||||
degree_c[Community(i)] +=
|
||||
static_cast<double>(IncidentWeight(i));
|
||||
for (const auto &neigh : adj_list_[i]) {
|
||||
uint32_t j = neigh.dest;
|
||||
double w = neigh.weight;
|
||||
if (Community(i) != Community(j)) continue;
|
||||
ret += w - (IncidentWeight(i) * IncidentWeight(j) / (2.0 * total_w_));
|
||||
weight_c[Community(i)] += w;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &p : degree_c)
|
||||
ret += weight_c[p.first] - (p.second * p.second) / (2 * total_w_);
|
||||
|
||||
ret /= 2 * total_w_;
|
||||
return ret;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ TEST(Graph, Modularity) {
|
||||
{3, 4, 4.2}});
|
||||
std::vector<uint32_t> c = {0, 1, 1, 2, 2};
|
||||
SetCommunities(&graph, c);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.37452886332076973, 1e-6);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.036798254314620096, 1e-6);
|
||||
|
||||
// Tree
|
||||
// (0)--(3)
|
||||
@ -289,7 +289,7 @@ TEST(Graph, Modularity) {
|
||||
{2, 6, 0.7}});
|
||||
c = {0, 0, 1, 0, 0, 1, 2};
|
||||
SetCommunities(&graph, c);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.6945087219651122, 1e-6);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.4424617301530794, 1e-6);
|
||||
|
||||
// Graph without self-loops
|
||||
// (0)--(1)
|
||||
@ -305,7 +305,7 @@ TEST(Graph, Modularity) {
|
||||
{3, 4, 0.7}});
|
||||
c = {0, 1, 1, 1, 1};
|
||||
SetCommunities(&graph, c);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.32653061224489793, 1e-6);
|
||||
EXPECT_NEAR(graph.Modularity(), -0.022959183673469507, 1e-6);
|
||||
|
||||
// Graph with self loop [*nodes have self loops]
|
||||
// (0)--(1*)
|
||||
@ -324,5 +324,42 @@ TEST(Graph, Modularity) {
|
||||
{4, 4, 1}});
|
||||
c = {0, 0, 0, 0, 1};
|
||||
SetCommunities(&graph, c);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.2754545454545455, 1e-6);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.188842975206611, 1e-6);
|
||||
|
||||
// Neo4j example graph
|
||||
// (0)--(1)---(3)--(4)
|
||||
// \ / \ /
|
||||
// (2) (5)
|
||||
graph = BuildGraph(6, {{0, 1, 1},
|
||||
{1, 2, 1},
|
||||
{0, 2, 1},
|
||||
{1, 3, 1},
|
||||
{3, 5, 1},
|
||||
{5, 4, 1},
|
||||
{3, 4, 1}});
|
||||
c = {0, 0, 0, 1, 1, 1};
|
||||
SetCommunities(&graph, c);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.3571428571428571, 1e-6);
|
||||
|
||||
// Example graph from wikipedia
|
||||
// (0)--(1)--(3)--(4)--(5)
|
||||
// \ / | \ /
|
||||
// (2) (7) (6)
|
||||
// / \
|
||||
// (8)--(9)
|
||||
graph = BuildGraph(10, {{0, 1, 1},
|
||||
{1, 2, 1},
|
||||
{0, 2, 1},
|
||||
{1, 3, 1},
|
||||
{3, 4, 1},
|
||||
{4, 5, 1},
|
||||
{5, 6, 1},
|
||||
{6, 4, 1},
|
||||
{3, 7, 1},
|
||||
{7, 8, 1},
|
||||
{7, 9, 1},
|
||||
{8, 9, 1}});
|
||||
c = {0, 0, 0, 0, 1, 1, 1, 2, 2, 2};
|
||||
SetCommunities(&graph, c);
|
||||
EXPECT_NEAR(graph.Modularity(), 0.4896, 1e-4);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user