Skip to content

Commit

Permalink
fix(analytical): clustering support undirected graph
Browse files Browse the repository at this point in the history
Signed-off-by: acezen <[email protected]>
  • Loading branch information
acezen committed Apr 17, 2024
1 parent 4a7e1ab commit dea5b3b
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 30 deletions.
85 changes: 55 additions & 30 deletions analytical_engine/apps/clustering/clustering.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
#ifndef ANALYTICAL_ENGINE_APPS_CLUSTERING_CLUSTERING_H_
#define ANALYTICAL_ENGINE_APPS_CLUSTERING_CLUSTERING_H_

#include <iostream>
#include <unordered_map>
#include <utility>
#include <vector>
Expand All @@ -26,8 +27,8 @@ limitations under the License.

namespace gs {
/**
* @brief An implementation of Clustering Coefficient for vertices, which only
* works on directed graphs. For undirected graphs, see grape::LCC.
* @brief An implementation of Clustering Coefficient for vertices. Support both
* directed and undirected graph.
*
* This app inherits ParallelAppBase. Messages can be sent in
* parallel to the evaluation. This strategy improve performance by overlapping
Expand Down Expand Up @@ -56,11 +57,20 @@ class Clustering
messages.InitChannels(thread_num());
ctx.stage = 0;
ForEach(inner_vertices, [&messages, &frag, &ctx](int tid, vertex_t v) {
ctx.global_degree[v] =
frag.GetLocalOutDegree(v) + frag.GetLocalInDegree(v);
if (frag.directed()) {
ctx.global_degree[v] = frag.GetLocalOutDegree(v) +
frag.GetLocalInDegree(v);
} else {
ctx.global_degree[v] = frag.GetLocalOutDegree(v);
}
if (ctx.global_degree[v] > 1) {
messages.SendMsgThroughEdges<fragment_t, int>(
frag, v, ctx.global_degree[v], tid);
if (frag.directed()) {
messages.SendMsgThroughEdges<fragment_t, int>(
frag, v, ctx.global_degree[v], tid);
} else {
messages.SendMsgThroughOEdges<fragment_t, int>(
frag, v, ctx.global_degree[v], tid);
}
}
});
messages.ForceContinue();
Expand Down Expand Up @@ -97,12 +107,15 @@ class Clustering
auto u = e.get_neighbor();
is_rec[u.GetValue()]++;
}
es = frag.GetIncomingAdjList(v);
for (auto& e : es) {
auto u = e.get_neighbor();
is_rec[u.GetValue()]++;
if (is_rec[u.GetValue()] == 2) {
ctx.rec_degree[v]++;

if (frag.directed()) {
es = frag.GetIncomingAdjList(v);
for (auto& e : es) {
auto u = e.get_neighbor();
is_rec[u.GetValue()]++;
if (is_rec[u.GetValue()] == 2) {
ctx.rec_degree[v]++;
}
}
}

Expand Down Expand Up @@ -136,35 +149,43 @@ class Clustering
}
}

es = frag.GetIncomingAdjList(v);
for (auto& e : es) {
auto u = e.get_neighbor();
if (ctx.global_degree[u] < ctx.global_degree[v]) {
std::pair<vid_t, uint32_t> msg;
msg.first = frag.Vertex2Gid(u);
if (is_rec[u.GetValue()] == 1) {
msg.second = 1;
msg_vec.push_back(msg);
nbr_vec.push_back(std::make_pair(u, 1));
}
} else if (ctx.global_degree[u] == ctx.global_degree[v]) {
u_gid = frag.Vertex2Gid(u);
v_gid = frag.GetInnerVertexGid(v);
if (v_gid > u_gid) {
if (frag.directed()) {
es = frag.GetIncomingAdjList(v);
for (auto& e : es) {
auto u = e.get_neighbor();
if (ctx.global_degree[u] < ctx.global_degree[v]) {
std::pair<vid_t, uint32_t> msg;
msg.first = frag.Vertex2Gid(u);
if (is_rec[u.GetValue()] == 1) {
msg.second = 1;
msg_vec.push_back(msg);
nbr_vec.push_back(std::make_pair(u, 1));
}
} else if (ctx.global_degree[u] == ctx.global_degree[v]) {
u_gid = frag.Vertex2Gid(u);
v_gid = frag.GetInnerVertexGid(v);
if (v_gid > u_gid) {
std::pair<vid_t, uint32_t> msg;
msg.first = frag.Vertex2Gid(u);
if (is_rec[u.GetValue()] == 1) {
msg.second = 1;
msg_vec.push_back(msg);
nbr_vec.push_back(std::make_pair(u, 1));
}
}
}
}
}

messages.SendMsgThroughEdges<fragment_t,
if (frag.directed()) {
messages.SendMsgThroughEdges<fragment_t,
std::vector<std::pair<vid_t, uint32_t>>>(
frag, v, msg_vec, tid);
frag, v, msg_vec, tid);
} else {
messages.SendMsgThroughOEdges<fragment_t,
std::vector<std::pair<vid_t, uint32_t>>>(
frag, v, msg_vec, tid);
}
}
});
messages.ForceContinue();
Expand Down Expand Up @@ -251,7 +272,11 @@ class Clustering
} else {
int degree =
global_degree[v] * (global_degree[v] - 1) - 2 * rec_degree[v];
ctx_data[v] = degree == 0 ? 0.0 : 1.0 * tricnt[v] / degree;
if (frag.directed()) {
ctx_data[v] = degree == 0 ? 0.0 : 1.0 * tricnt[v] / degree;
} else {
ctx_data[v] = degree == 0 ? 0.0 : 2.0 * tricnt[v] / degree;
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions python/graphscope/nx/tests/test_ctx_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ def test_hits(self):
def test_clustering(self):
ans = nx.builtin.clustering(self.p2p)
self.assert_result_almost_equal(ans, self.p2p_clus_ans)
# test undirected graph
G = nx.Graph()
G.add_nodes_from([1, 2, 3])
G.add_edges_from([(1, 2), (2, 3), (3, 1)])
nx.builtin.clustering(G) == {1: 1.0, 2: 1.0, 3: 1.0}

def test_triangles(self):
ans = nx.builtin.triangles(self.p2p_undirected)
Expand Down

0 comments on commit dea5b3b

Please sign in to comment.