#include "path.h" #ifdef _OPENMP #include #endif #include "../../classes/graph.h" #include "../../common/utils.h" #include "../../classes/linkgraph.h" #include #include #include #include double _bfs_sum(const Graph_L& G_l, int source) { int N = G_l.n; std::vector dis(N + 1, -1); std::queue q; dis[source] = 0; q.push(source); double sum = 0.0; int visited_count = 0; const std::vector& head = G_l.head; const std::vector& E = G_l.edges; while (!q.empty()) { int u = q.front(); q.pop(); sum += dis[u]; visited_count++; for (int p = head[u]; p != -1; p = E[p].next) { int v = E[p].to; if (dis[v] == -1) { dis[v] = dis[u] + 1; q.push(v); } } } return (visited_count == N) ? sum : -1.0; } double _dijkstra_sum(const Graph_L& G_l, int source) { 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}); double sum = 0.0; int visited_count = 0; const std::vector& head = G_l.head; const std::vector& E = G_l.edges; while (!pq.empty()) { auto top_node = pq.top(); double d = top_node.first; int u = top_node.second; pq.pop(); if (d > dis[u]) continue; sum += d; visited_count++; 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 (visited_count == N) ? sum : -1.0; } py::object average_shortest_path_length(py::object G, py::object weight, py::object method) { Graph& G_ = G.cast(); bool is_directed = G.attr("is_directed")().cast(); std::string weight_key = ""; if (!weight.is_none()) { weight_key = weight.cast(); } std::string method_str; if (method.is_none()) { method_str = weight.is_none() ? "single_source_bfs" : "dijkstra"; } else { method_str = method.cast(); } if(G_.linkgraph_dirty){ G_.linkgraph_structure = graph_to_linkgraph(G_, is_directed, weight_key, true, false); G_.linkgraph_dirty = false; } const Graph_L& G_l = G_.linkgraph_structure; int N = G_l.n; if (N <= 1) return py::float_(0.0); double total_sum = 0.0; bool is_connected = true; { py::gil_scoped_release release; #pragma omp parallel for reduction(+:total_sum) schedule(dynamic) for (int i = 1; i <= N; i++) { if (!is_connected) continue; double local_sum = 0.0; if (method_str == "single_source_bfs" || method_str == "unweighted") { local_sum = _bfs_sum(G_l, i); } else { local_sum = _dijkstra_sum(G_l, i); } if (local_sum < 0) { #pragma omp critical is_connected = false; } else { total_sum += local_sum; } } } if (!is_connected) { if (is_directed) { throw py::value_error("Graph is not strongly connected."); } else { throw py::value_error("Graph is not connected."); } } return py::float_(total_sum / (static_cast(N) * (N - 1))); }