#include "centrality.h" #ifdef EASYGRAPH_ENABLE_GPU #include #endif #include "../../classes/graph.h" #include "../../common/utils.h" #include "../../classes/linkgraph.h" #include "../../classes/segment_tree.cpp" void betweenness_dijkstra(const Graph_L& G_l, const int &S, std::vector& bc, double cutoff, Segment_tree_zkw& segment_tree_zkw, int endpoints_) { const int dis_inf = 0x3f3f3f3f; int N = G_l.n; int edge_number_path = 0; segment_tree_zkw.init(N); std::vector dis(N+1, INT_MAX); std::vector head_path(N+1, 0); const std::vector& head = G_l.head; const std::vector& E = G_l.edges; int edges_num = E.size(); std::vector St(N+1, 0); std::vector count_path(N+1, 0); std::vector delta(N+1, 0); std::vector E_path(edges_num+1); head_path[S] = 0; dis[S] = 0; count_path[S] = 1; segment_tree_zkw.change(S, 0); int cnt_St = 0; while(segment_tree_zkw.t[1] != dis_inf) { int u = segment_tree_zkw.num[1]; if(u==0) break; segment_tree_zkw.change(u, dis_inf); if (cutoff >= 0 && dis[u] > cutoff){ continue; } St[cnt_St++] = u; for(int p = head[u]; p != -1; p = E[p].next) { int v = E[p].to; if(cutoff >= 0 && (dis[u] + E[p].w) > cutoff){ continue; } if (dis[v] > dis[u] + E[p].w) { dis[v] = dis[u] + E[p].w; segment_tree_zkw.change(v, dis[v]); count_path[v] = count_path[u]; head_path[v] = 0; E_path[++edge_number_path].next = head_path[v]; E_path[edge_number_path].to = u; head_path[v] = edge_number_path; } else if (dis[v] == dis[u] + E[p].w) { count_path[v] += count_path[u]; E_path[++edge_number_path].next = head_path[v]; E_path[edge_number_path].to = u; head_path[v] = edge_number_path; } } } if (endpoints_) { bc[S] += cnt_St - 1; } while (cnt_St > 0) { int u = St[--cnt_St]; float coeff = (1.0 + delta[u]) / count_path[u]; for(int p = head_path[u]; p; p = E_path[p].next){ delta[E_path[p].to] += count_path[E_path[p].to] * coeff; } if (u != S) bc[u] += delta[u] + endpoints_; } } static double calc_scale(int len_V, int is_directed, int normalized, int endpoints) { double scale = 1.0; if (normalized) { if (endpoints) { if (len_V < 2) { scale = 1.0; } else { scale = 1.0 / (double(len_V) * (len_V - 1)); } } else if (len_V <= 2) { scale = 1.0; } else { scale = 1.0 / ((double(len_V) - 1) * (len_V - 2)); } } else { if (!is_directed) { scale = 0.5; } else { scale = 1.0; } } return scale; } static py::object invoke_cpp_betweenness_centrality(py::object G, py::object weight, py::object cutoff, py::object sources, py::object normalized, py::object endpoints){ Graph& G_ = G.cast(); int cutoff_ = -1; if (!cutoff.is_none()){ cutoff_ = cutoff.cast(); } int N = G_.node.size(); bool is_directed = G.attr("is_directed")().cast(); int normalized_ = normalized.cast(); int endpoints_ = endpoints.cast(); double scale = calc_scale(N, is_directed, normalized_, endpoints_); std::string weight_key = weight_to_string(weight); Graph_L G_l; if(G_.linkgraph_dirty){ G_l = graph_to_linkgraph(G_, is_directed, weight_key, false, false); G_.linkgraph_structure=G_l; G_.linkgraph_dirty = false; } else{ G_l = G_.linkgraph_structure; } Segment_tree_zkw segment_tree_zkw(N); std::vector bc(N+1, 0); py::list res_lst = py::list(); if(!sources.is_none()){ py::list sources_list = py::list(sources); int sources_list_len = py::len(sources_list); for(register int i = 0; i < sources_list_len; i++){ if(G_.node_to_id.attr("get")(sources_list[i],py::none()).is_none()){ printf("The node should exist in the graph!"); return py::none(); } py::list res_lst = py::list(); node_t source_id = G_.node_to_id.attr("get")(sources_list[i]).cast(); betweenness_dijkstra(G_l, source_id, bc, cutoff_, segment_tree_zkw, endpoints_); } for(int i = 1; i <= N; i++){ res_lst.append(scale * bc[i]); } } else{ for (int i = 1; i <= N; ++i){ betweenness_dijkstra(G_l, i, bc, cutoff_,segment_tree_zkw, endpoints_); } for(int i = 1; i <= N; i++){ res_lst.append(scale * bc[i]); } } py::list py_nodes_order; std::vector node_idx; for (auto it = G_.node.begin(); it != G_.node.end(); ++it) { node_idx.push_back(it->first); } std::sort(node_idx.begin(), node_idx.end()); for (int i = 0; i < node_idx.size(); ++i) { py_nodes_order.append(G_.id_to_node[py::cast(node_idx[i])]); } py::list ret; ret.append(py_nodes_order); ret.append(res_lst); return ret; } #ifdef EASYGRAPH_ENABLE_GPU static py::object invoke_gpu_betweenness_centrality(py::object G, py::object weight, py::object py_sources, py::object normalized, py::object endpoints) { Graph& G_ = G.cast(); py::list py_nodes_order; std::vector E; std::vector V; std::vector W; std::vector sources; std::vector BC; bool is_directed = G.attr("is_directed")().cast(); G_.gen_CSR(weight, py_sources, py_nodes_order, V, E, W, sources); int gpu_r = gpu_easygraph::betweenness_centrality(V, E, W, sources, is_directed, normalized.cast(), endpoints.cast(), BC); if (gpu_r != gpu_easygraph::EG_GPU_SUCC) { // the code below will throw an exception py::pybind11_fail(gpu_easygraph::err_code_detail(gpu_r)); } py::list ret_val; for (int i = 0; i < BC.size(); ++i) { ret_val.append(BC[i]); } py::list ret; ret.append(py_nodes_order); ret.append(ret_val); return ret; } #endif py::object betweenness_centrality(py::object G, py::object weight, py::object cutoff, py::object sources, py::object normalized, py::object endpoints) { #ifdef EASYGRAPH_ENABLE_GPU return invoke_gpu_betweenness_centrality(G, weight, sources, normalized, endpoints); #else return invoke_cpp_betweenness_centrality(G, weight, cutoff, sources, normalized, endpoints); #endif } // void betweenness_dijkstra(const Graph_L& G_l, const int &S, std::vector& bc, double cutoff) { // int N = G_l.n; // int edge_number_path = 0; // __gnu_pbds::priority_queue q; // std::vector dis(N+1, INFINITY); // std::vector vis(N+1, false); // std::vector head_path(N+1, 0); // const std::vector& head = G_l.head; // const std::vector& E = G_l.edges; // int edges_num = E.size(); // std::vector St(N+1, 0); // std::vector count_path(N+1, 0); // std::vector delta(N+1, 0); // std::vector E_path(edges_num+1); // head_path[S] = 0; // dis[S] = 0; // count_path[S] = 1; // q.push(compare_node(S, 0)); // int cnt_St = 0; // while(!q.empty()) { // int u = q.top().x; // q.pop(); // if (vis[u]){ // continue; // } // if (cutoff >= 0 && dis[u] > cutoff){ // continue; // } // St[cnt_St++] = u; // vis[u] = true; // for(int p = head[u]; p != -1; p = E[p].next) { // int v = E[p].to; // if(cutoff >= 0 && (dis[u] + E[p].w) > cutoff){ // continue; // } // if (dis[v] > dis[u] + E[p].w) { // dis[v] = dis[u] + E[p].w; // q.push(compare_node(v, dis[v])); // count_path[v] = count_path[u]; // head_path[v] = 0; // E_path[++edge_number_path].next = head_path[v]; // E_path[edge_number_path].to = u; // head_path[v] = edge_number_path; // } // else if (dis[v] == dis[u] + E[p].w) { // count_path[v] += count_path[u]; // E_path[++edge_number_path].next = head_path[v]; // E_path[edge_number_path].to = u; // head_path[v] = edge_number_path; // } // } // } // while (cnt_St > 0) { // int u = St[--cnt_St]; // float coeff = (1.0 + delta[u]) / count_path[u]; // for(int p = head_path[u]; p; p = E_path[p].next){ // delta[E_path[p].to] += count_path[E_path[p].to] * coeff; // } // if (u != S) // bc[u] += delta[u]; // } // }