#include "path.h" #ifdef _OPENMP #include #endif #ifdef EASYGRAPH_ENABLE_GPU #include #endif #include "../../classes/graph.h" #include "../../common/utils.h" #include "../../classes/linkgraph.h" #include "../../classes/segment_tree.cpp" #include #include #include #include std::vector _dijkstra(const Graph_L& G_l, int source, int target) { int N = G_l.n; const double INF = std::numeric_limits::infinity(); std::vector dis(N + 1, INF); std::priority_queue, std::vector>, std::greater>> pq; dis[source] = 0.0; pq.push({0.0, source}); const std::vector& head = G_l.head; const std::vector& E = G_l.edges; while (!pq.empty()) { std::pair top = pq.top(); pq.pop(); double d = top.first; int u = top.second; //Lazy deletion if (d > dis[u]) continue; // cutoff if (u == target) break; for (int p = head[u]; p != -1; p = E[p].next) { int v = E[p].to; double w = static_cast(E[p].w); if (dis[u] + w < dis[v]) { dis[v] = dis[u] + w; pq.push({dis[v], v}); } } } return dis; } py::object _invoke_cpp_dijkstra_multisource(py::object G, py::object sources, py::object weight, py::object target) { bool is_directed = G.attr("is_directed")().cast(); Graph& G_ = G.cast(); 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, true, false); G_.linkgraph_structure = G_l; G_.linkgraph_dirty = false; } else { G_l = G_.linkgraph_structure; } node_t target_id = -1; if (!target.is_none()) { target_id = G_.node_to_id.attr("get")(target, -1).cast(); } py::list sources_list = py::list(sources); int num_sources = py::len(sources_list); int N = G_l.n; std::vector source_ids(num_sources); for(int i = 0; i < num_sources; i++){ if(G_.node_to_id.attr("get")(sources_list[i], py::none()).is(py::none())){ printf("The node should exist in the graph!"); return py::none(); } source_ids[i] = G_.node_to_id.attr("get")(sources_list[i]).cast(); } std::vector results(num_sources * N); { py::gil_scoped_release release; #pragma omp parallel for schedule(dynamic) for (int i = 0; i < num_sources; i++) { node_t s = source_ids[i]; std::vector dists = _dijkstra(G_l, s, target_id); size_t offset = (size_t)i * N; for (int j = 1; j <= N; j++) { results[offset + (j - 1)] = dists[j]; } } } py::array::ShapeContainer ret_shape{num_sources, N}; py::array_t ret(ret_shape, results.data()); return ret; } #ifdef EASYGRAPH_ENABLE_GPU py::object _invoke_gpu_dijkstra_multisource(py::object G,py::object py_sources, py::object weight, py::object target) { Graph& G_ = G.cast(); if (weight.is_none()) { G_.gen_CSR(); } else { G_.gen_CSR(weight_to_string(weight)); } auto csr_graph = G_.csr_graph; std::vector& E = csr_graph->E; std::vector& V = csr_graph->V; std::vector *W_p = weight.is_none() ? &(csr_graph->unweighted_W) : csr_graph->W_map.find(weight_to_string(weight))->second.get(); auto sources = G_.gen_CSR_sources(py_sources); std::vector sssp; int gpu_r = gpu_easygraph::sssp_dijkstra(V, E, *W_p, *sources, target.is_none() ? -1 : (int)py::cast(target), sssp); 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::array::ShapeContainer ret_shape{(int)sources->size(), (int)V.size() - 1}; py::array_t ret(ret_shape, sssp.data()); return ret; } #endif py::object _dijkstra_multisource(py::object G,py::object sources, py::object weight, py::object target) { #ifdef EASYGRAPH_ENABLE_GPU return _invoke_gpu_dijkstra_multisource(G, sources, weight, target); #else return _invoke_cpp_dijkstra_multisource(G, sources, weight, target); #endif } py::object _spfa(py::object G, py::object source, py::object weight) { Graph& G_ = G.cast(); bool is_directed = G.attr("is_directed")().cast(); std::string weight_key = weight_to_string(weight); Graph_L G_l = graph_to_linkgraph(G_, is_directed,weight_key, false); int N = G_.node.size(); std::vector Q(N+10,0); std::vector dis(N+1,INFINITY); std::vector vis(N+1,false); int l = 0, r = 1; node_t S = G_.node_to_id[source].cast(); Q[0] = S; vis[S] = true; dis[S] = 0; std::vector& E = G_l.edges; std::vector& head = G_l.head; while (l != r) { if (r != 0 && dis[Q[l]] >= dis[Q[r - 1]]) std::swap(Q[l], Q[r - 1]); int u = Q[l++]; if (l >= N) l -= N; vis[u] = true; for(int p = head[u]; p != -1; p = E[p].next) { int v=E[p].to; if (dis[v]>dis[u]+E[p].w) { dis[v]=dis[u]+E[p].w; if (!vis[v]) { vis[v]=true; if (l == 0 || dis[v] >= dis[Q[l]]) Q[r++]=v; else Q[--l]=v; if (r >= N) r -= N; } } } } py::list pydist = py::list(); for(int i = 1; i <= N; i++){ pydist.append(py::cast(dis[i])); } return pydist; } py::object Prim(py::object G, py::object weight) { std::unordered_map> res_dict; py::dict result_dict = py::dict(); Graph& G_ = G.cast(); adj_dict_factory adj = G_.adj; std::vector selected; std::vector candidate; node_dict_factory& node_list = G_.node; std::string weight_key = weight_to_string(weight); for (node_dict_factory::iterator i = node_list.begin(); i != node_list.end(); i++) { node_t node_id = i->first; result_dict[G_.id_to_node[py::cast(node_id)]] = py::dict(); if (selected.size() == 0) { selected.emplace_back(node_id); } else { candidate.emplace_back(node_id); } } while (candidate.size() > 0) { node_t start_id = -1; node_t end_id = -1; weight_t min_weight = INFINITY; int selected_len = selected.size(); int candidate_len = candidate.size(); for (int i = 0; i < selected_len; i++) { for (int j = 0; j < candidate_len; j++) { adj_attr_dict_factory node_adj = G_.adj[selected[i]]; edge_attr_dict_factory edge_attr; weight_t edge_weight = INFINITY; bool j_exist = false; if (node_adj.find(candidate[j]) != node_adj.end()) { edge_attr = node_adj[candidate[j]]; edge_weight = edge_attr.find(weight_key) != edge_attr.end() ? edge_attr[weight_key] : 1; j_exist = true; } if ((node_list.find(selected[i]) != node_list.end()) && j_exist && (edge_weight < min_weight)) { start_id = selected[i]; end_id = candidate[j]; min_weight = edge_weight; } } } if (start_id != -1 && end_id != -1) { res_dict[start_id][end_id] = min_weight; selected.emplace_back(end_id); std::vector::iterator temp_iter; temp_iter = std::find(candidate.begin(), candidate.end(), end_id); candidate.erase(temp_iter); } else { break; } } for (std::unordered_map>::iterator k = res_dict.begin(); k != res_dict.end(); k++) { py::object res_node = G_.id_to_node[py::cast(k->first)]; for (std::unordered_map::iterator z = k->second.begin(); z != k->second.end(); z++) { py::object res_adj_node = G_.id_to_node[py::cast(z->first)]; result_dict[res_node][res_adj_node] = z->second; } } return result_dict; } bool comp(const std::pair, weight_t>& a, const std::pair, weight_t>& b) { return a.second < b.second; } py::object Kruskal(py::object G, py::object weight) { std::unordered_map> res_dict; py::dict result_dict = py::dict(); std::vector> group; Graph& G_ = G.cast(); adj_dict_factory& adj = G_.adj; node_dict_factory& node_list = G_.node; std::vector, weight_t>> edge_list; std::string weight_key = weight_to_string(weight); for (node_dict_factory::iterator i = node_list.begin(); i != node_list.end(); i++) { node_t i_id = i->first; result_dict[G_.id_to_node[py::cast(i_id)]] = py::dict(); std::vector temp_vector; temp_vector.emplace_back(i_id); group.emplace_back(temp_vector); adj_attr_dict_factory i_adj = adj[i_id]; for (adj_attr_dict_factory::iterator j = i_adj.begin(); j != i_adj.end(); j++) { node_t j_id = j->first; weight_t edge_weight = adj[i_id][j_id].find(weight_key) != adj[i_id][j_id].end() ? adj[i_id][j_id][weight_key] : 1; edge_list.emplace_back(std::make_pair(std::make_pair(i_id, j_id), edge_weight)); } } std::sort(edge_list.begin(), edge_list.end(), comp); node_t m, n; int group_size = group.size(); for (auto edge : edge_list) { for (int i = 0; i < group_size; i++) { int group_i_size = group[i].size(); for (int j = 0; j < group_i_size; j++) { if (group[i][j] == edge.first.first) { m = i; break; } } for (int j = 0; j < group_i_size; j++) { if (group[i][j] == edge.first.second) { n = i; break; } } } if (m != n) { res_dict[edge.first.first][edge.first.second] = edge.second; std::vector temp_vector; group[m].insert(group[m].end(), group[n].begin(), group[n].end()); group[n].clear(); } } for (std::unordered_map>::iterator k = res_dict.begin(); k != res_dict.end(); k++) { py::object res_node = G_.id_to_node[py::cast(k->first)]; for (std::unordered_map::iterator z = k->second.begin(); z != k->second.end(); z++) { py::object res_adj_node = G_.id_to_node[py::cast(z->first)]; result_dict[res_node][res_adj_node] = z->second; } } return result_dict; } py::object Floyd(py::object G, py::object weight) { std::unordered_map> res_dict; Graph& G_ = G.cast(); adj_dict_factory& adj = G_.adj; py::dict result_dict = py::dict(); node_dict_factory& node_list = G_.node; std::string weight_key = weight_to_string(weight); for (node_dict_factory::iterator i = node_list.begin(); i != node_list.end(); i++) { result_dict[G_.id_to_node[py::cast(i->first)]] = py::dict(); adj_attr_dict_factory temp_key = adj[i->first]; for (node_dict_factory::iterator j = node_list.begin(); j != node_list.end(); j++) { if (temp_key.find(j->first) != temp_key.end()) { if (adj[i->first][j->first].count(weight_key) == 0) { adj[i->first][j->first][weight_key] = 1; } res_dict[i->first][j->first] = adj[i->first][j->first][weight_key]; } else { res_dict[i->first][j->first] = INFINITY; } if (i->first == j->first) { res_dict[i->first][i->first] = 0; } } } for (node_dict_factory::iterator k = node_list.begin(); k != node_list.end(); k++) { for (node_dict_factory::iterator i = node_list.begin(); i != node_list.end(); i++) { for (node_dict_factory::iterator j = node_list.begin(); j != node_list.end(); j++) { weight_t temp = res_dict[i->first][k->first] + res_dict[k->first][j->first]; weight_t i_j_weight = res_dict[i->first][j->first]; if (i_j_weight > temp) { res_dict[i->first][j->first] = temp; } } } } for (std::unordered_map>::iterator k = res_dict.begin(); k != res_dict.end(); k++) { py::object res_node = G_.id_to_node[py::cast(k->first)]; for (std::unordered_map::iterator z = k->second.begin(); z != k->second.end(); z++) { py::object res_adj_node = G_.id_to_node[py::cast(z->first)]; result_dict[res_node][res_adj_node] = z->second; } } return result_dict; }