chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:36:30 +08:00
commit 55ab4e4a73
473 changed files with 72932 additions and 0 deletions
@@ -0,0 +1,5 @@
#pragma once
#include "biconnected.h"
#include "connected.h"
#include "strongly_connected.h"
@@ -0,0 +1,109 @@
#include "biconnected.h"
#include "../../classes/graph.h"
#include "../../common/utils.h"
node_t index_edge(std::vector<std::pair<node_t, node_t>>& edges, const std::pair<node_t, node_t>& target) {
for (int i = edges.size() - 1;i >= 0;i--) {
if ((edges[i].first == target.first) && (edges[i].second == target.second)) {
return i;
}
}
return -1;
}
py::object _biconnected_dfs_record_edges(py::object G, py::object need_components) {
py::list ret = py::list();
std::unordered_set<node_t> visited;
Graph& G_ = G.cast<Graph&>();
node_dict_factory &nodes_list = G_.node;
for (node_dict_factory::iterator iter = nodes_list.begin();iter != nodes_list.end();iter++) {
node_t start_id = iter->first;
if (visited.find(start_id) != visited.end()) {
continue;
}
std::unordered_map<node_t, int> discovery;
std::unordered_map<node_t, int> low;
node_t root_children = 0;
discovery.emplace(start_id, 0);
low.emplace(start_id, 0);
visited.emplace(start_id);
std::vector<std::pair<node_t, node_t>> edge_stack;
std::vector<stack_node> stack;
adj_attr_dict_factory& start_adj = G_.adj[start_id];
NeighborIterator neighbors_iter = NeighborIterator(start_adj);
stack_node initial_stack_node(start_id, start_id, neighbors_iter);
stack.emplace_back(initial_stack_node);
while (!stack.empty()) {
stack_node& node_info = stack.back();
node_t node_grandparent_id = node_info.grandparent;
node_t node_parent_id = node_info.parent;
try {
node_t node_child_id = node_info.neighbors_iter.next();
if (node_grandparent_id == node_child_id) {
continue;
}
if (visited.find(node_child_id) != visited.end()) {
if (discovery[node_child_id] <= discovery[node_parent_id]) {
low[node_parent_id] = std::min(low[node_parent_id], discovery[node_child_id]);
if (need_components.cast<bool>()) {
edge_stack.emplace_back(std::make_pair(node_parent_id, node_child_id));
}
}
}
else {
low[node_child_id] = discovery[node_child_id] = discovery.size();
visited.emplace(node_child_id);
adj_attr_dict_factory& node_child_adj = G_.adj[node_child_id];
NeighborIterator child_neighbors_iter = NeighborIterator(G_.adj[node_child_id]);
stack.emplace_back(node_parent_id, node_child_id, child_neighbors_iter);
if (need_components.cast<bool>()) {
edge_stack.emplace_back(std::make_pair(node_parent_id, node_child_id));
}
}
}
catch (int) {
stack.pop_back();
if (stack.size() > 1) {
if (low[node_parent_id] >= discovery[node_grandparent_id]) {
if (need_components.cast<bool>()) {
py::list tmp_ret = py::list();
std::pair<node_t, node_t> iter_edge = std::make_pair(-1, -1);
while ((iter_edge.first != node_grandparent_id || iter_edge.second != node_parent_id)) {
iter_edge = edge_stack.back();
edge_stack.pop_back();
tmp_ret.append(py::make_tuple(G_.id_to_node[py::cast(iter_edge.first)], G_.id_to_node[py::cast(iter_edge.second)]));
}
ret.append(tmp_ret);
}
else {
ret.append(G_.id_to_node[py::cast(node_grandparent_id)]);
}
}
low[node_grandparent_id] = std::min(low[node_grandparent_id], low[node_parent_id]);
}
else if (stack.size() > 0) {
root_children += 1;
if (need_components.cast<bool>()) {
std::pair<node_t, node_t> target = std::make_pair(node_grandparent_id, node_parent_id);
node_t ind = index_edge(edge_stack, target);
if (ind != -1) {
py::list tmp_ret = py::list();
for (node_t z = ind;z < edge_stack.size();z++) {
tmp_ret.append(py::make_tuple(G_.id_to_node[py::cast(edge_stack[z].first)], G_.id_to_node[py::cast(edge_stack[z].second)]));
}
ret.append(tmp_ret);
}
}
}
}
}
if (!need_components.cast<bool>()) {
if (root_children > 1) {
ret.append(G_.id_to_node(start_id));
}
}
}
return ret;
}
@@ -0,0 +1,34 @@
#pragma once
#include "../../common/common.h"
class NeighborIterator {
public:
NeighborIterator() {
}
NeighborIterator(adj_attr_dict_factory& neighbor_map) {
now = neighbor_map.begin();;
end = neighbor_map.end();
}
node_t next() {
if (now == end) {
throw -1;
}
else {
return (now++)->first;
}
}
private:
adj_attr_dict_factory::iterator now, end;
};
typedef struct stackNode {
node_t grandparent, parent;
NeighborIterator neighbors_iter;
stackNode(node_t grandparent, node_t parent, NeighborIterator neighbors_iter) {
this->grandparent = grandparent;
this->parent = parent;
this->neighbors_iter = neighbors_iter;
}
}stack_node;
py::object _biconnected_dfs_record_edges(py::object G, py::object need_components);
@@ -0,0 +1,205 @@
#include "connected.h"
#include <pybind11/stl.h>
#include "../../classes/graph.h"
#include "../../classes/directed_graph.h"
#include "../../common/utils.h"
#include "time.h"
#define gmin(x, y) x = x < y? x: y
py::object plain_bfs(py::object G, py::object source) {
Graph& G_ = G.cast<Graph&>();
node_t source_id = G_.node_to_id.attr("get")(source).cast<node_t>();
adj_dict_factory& G_adj = G_.adj;
std::unordered_set<node_t> seen;
std::unordered_set<node_t> nextlevel;
nextlevel.emplace(source_id);
py::list res = py::list();
while (nextlevel.size()) {
std::unordered_set<node_t> thislevel = nextlevel;
nextlevel = std::unordered_set<node_t>();
for (std::unordered_set<node_t>::iterator i = thislevel.begin(); i != thislevel.end(); i++) {
node_t v_id = *i;
if (seen.find(v_id) == seen.end()) {
seen.emplace(v_id);
adj_attr_dict_factory& v_adj = G_adj[v_id];
for (adj_attr_dict_factory::iterator j = v_adj.begin(); j != v_adj.end(); j++) {
node_t neighbor_id = j->first;
nextlevel.emplace(neighbor_id);
}
}
}
}
for (std::unordered_set<node_t>::iterator i = seen.begin(); i != seen.end(); i++) {
node_t res_id = *(i);
res.append(G_.id_to_node.attr("get")(res_id));
}
return res;
}
py::object connected_component_undirected(py::object G) {
Graph& G_ = G.cast<Graph&>();
bool is_directed = G.attr("is_directed")().cast<bool>();
if (is_directed == true) {
printf("connected_component_undirected is designed for undirected graphs.\n");
return py::dict();
}
int N = G_.node.size();
int M = G.attr("number_of_edges")().cast<int>();
std::vector<Edge_weighted> E_res(N+5);
for(int i=0; i < N+5; i++) {
E_res[i].toward = 0;
E_res[i].next = 0;
}
int edge_number_res = 0;
std::vector<int> parent(N+5, 0);
std::vector<int> rank_node(N+5, 0);
std::vector<int> color(N+5, 0);
std::vector<int> head_res(N+5, 0);
std::vector<bool> has_edge(N+5, false);
py::list nodes_list = py::list(G.attr("nodes"));
for (int i = 0;i < py::len(nodes_list);i++) {
node_t i_id = (G_.node_to_id[nodes_list[i]]).cast<node_t>();
parent[i_id] = i_id;
}
for (graph_edge& edge : G_._get_edges()) {
node_t u = edge.u, v = edge.v;
has_edge[u] = true; has_edge[v] = true;
_union_node(u, v, parent, rank_node);
}
int Tot = 0;
for(int i = 1; i < N + 1; ++i) {
if (!has_edge[i])
continue;
int fx = _getfa(i, parent);
if(fx == i){
color[++Tot] = fx;
}
}
for (int i = 1; i < N + 1; ++i) {
int fx = _getfa(i, parent);
_add_edge_res(fx, i, E_res, head_res, &edge_number_res);
}
py::dict ret = py::dict();
for (int i = 1; i <= Tot; ++i) {
py::list tmp = py::list();
for(int p = head_res[color[i]]; p; p = E_res[p].next){
tmp.append(py::cast(E_res[p].toward));
}
ret[py::cast(i)] = tmp;
}
return ret;
}
inline void _union_node(const int &u, const int &v, std::vector<int> &parent, std::vector<int> &rank_node) {
int x = _getfa(u, parent), y = _getfa(v, parent); //先找到两个根节点
if (rank_node[x] <= rank_node[y])
parent[x] = y;
else
parent[y] = x;
if (rank_node[x] == rank_node[y] && x != y)
rank_node[y]++; //如果深度相同且根节点不同,则新的根节点的深度+1
}
int _getfa(const int & x, std::vector<int> &parent) {
int r,k,t;
r=x;
while(parent[r]!=r)
r=parent[r];
k=r;
r=x;
while(parent[r]!=k) {
t=parent[r];
parent[r]=k;
r=t;
}
return k;
}
py::object connected_component_directed(py::object G) {
bool is_directed = G.attr("is_directed")().cast<bool>();
if (is_directed == false) {
printf("connected_component_directed is designed for directed graphs.\n");
return py::list();
}
DiGraph& G_ = G.cast<DiGraph&>();
int N = G_.node.size();
Graph_L G_l;
if(G_.linkgraph_dirty || G_.linkgraph_structure.max_deg == -1){
G_l = graph_to_linkgraph(G_, is_directed, "", true, false);
G_.linkgraph_dirty = false;
}
else{
G_l = G_.linkgraph_structure;
}
std::vector<LinkEdge>& E = G_l.edges;
std::vector<int> outDegree = G_l.degree;
std::vector<int> head = G_l.head;
int Time = 0, cnt = 0, Tot = 0, edge_number_res = 0;
std::vector<int> dfn(N+5, 0);
std::vector<int> low(N+5, 0);
std::vector<int> st(N+5, 0);
std::vector<int> color(N+5, 0);
std::vector<int> head_res(N+5, 0);
std::vector<bool> in_stack(N+5, false);
std::vector<bool> has_edge(N+5, false);
std::vector<Edge_weighted> E_res(N+5);
for(int i=0; i < N+5; i++) {
E_res[i].toward = 0;
E_res[i].next = 0;
}
for (graph_edge& edge : G_._get_edges()) {
node_t u = edge.u, v = edge.v;
has_edge[u] = true; has_edge[v] = true;
}
for (int i = 1; i < N + 1; ++i)
if (!dfn[i] && has_edge[i])
_tarjan(i, &Time, &cnt, &Tot, E, head, dfn, low, st, color, in_stack, E_res, head_res, &edge_number_res);
py::list ret = py::list();
for (int i = 1; i <= Tot; ++i) {
py::set tmp;
for(int p = head_res[i]; p; p = E_res[p].next)
tmp.add(G_.id_to_node.attr("get")(E_res[p].toward));
ret.append(tmp);
}
return ret;
}
void _add_edge_res(const int &u, const int &v, std::vector<Edge_weighted> &E_res, std::vector<int> &head_res, int *edge_number_res) {
E_res[++(*edge_number_res)].next = head_res[u];
E_res[*edge_number_res].toward = v;
head_res[u] = *edge_number_res;
}
void _tarjan(const int &u, int *Time, int *cnt, int *Tot, std::vector<LinkEdge>& E, std::vector<int>& head, std::vector<int> &dfn, std::vector<int> &low, std::vector<int> &st, std::vector<int> &color, std::vector<bool> &in_stack, std::vector<Edge_weighted> &E_res, std::vector<int> &head_res, int *edge_number_res) {
dfn[u] = low[u] = ++(*Time); st[++(*cnt)] = u; in_stack[u] = true;
for(int p = head[u]; p != -1; p = E[p].next){
int v = E[p].to;
if (!dfn[v]) _tarjan(v, Time, cnt, Tot, E, head, dfn, low, st, color, in_stack, E_res, head_res, edge_number_res), gmin(low[u], low[v]);
else if (in_stack[v]) gmin(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
for (++(*Tot); st[*cnt] != u; --(*cnt)) {
_add_edge_res(*Tot, st[*cnt], E_res, head_res, edge_number_res);
in_stack[st[*cnt]] = false, color[st[*cnt]] = *Tot;
}
_add_edge_res(*Tot, st[*cnt], E_res, head_res, edge_number_res);
in_stack[u] = false; color[u] = *Tot; --(*cnt);
}
}
@@ -0,0 +1,16 @@
#pragma once
#include "../../common/common.h"
#include "../../classes/linkgraph.h"
struct Edge_weighted{
int toward, next;
};
py::object plain_bfs(py::object G, py::object source);
py::object connected_component_undirected(py::object G);
inline void _union_node(const int &u, const int &v, std::vector<int>& parent, std::vector<int> &rank_node);
int _getfa(const int & x, std::vector<int> &parent);
py::object connected_component_directed(py::object G);
void _tarjan(const int &u, int *Time, int *cnt, int *Tot, std::vector<LinkEdge>& E, std::vector<int>& head, std::vector<int> &dfn, std::vector<int> &low, std::vector<int> &st, std::vector<int> &color, std::vector<bool> &in_stack, std::vector<Edge_weighted> &E_res, std::vector<int> &head_res, int *edge_number_res);
void _add_edge_res(const int &u, const int &v, std::vector<Edge_weighted> &E_res, std::vector<int> &head_res, int *edge_number_res);
@@ -0,0 +1,90 @@
#include "strongly_connected.h"
#include "connected.h"
#include "../../classes/directed_graph.h"
#define MAX_NODES_NUM4RECURSION_METHOD 100000
py::object strongly_connected_components(py::object G) {
bool is_directed = G.attr("is_directed")().cast<bool>();
if (is_directed == false) {
printf("connected_component_directed is designed for directed graphs.\n");
return py::list();
}
int N = G.attr("number_of_nodes")().cast<int>();
if(N < MAX_NODES_NUM4RECURSION_METHOD){
return connected_component_directed(G);
}
return strongly_connected_components_iteration_impl(G);
}
py::object strongly_connected_components_iteration_impl(py::object G) {
py::list res = py::list();
DiGraph& G_ = py::cast<DiGraph&>(G);
adj_dict_factory& adj = G_.adj;
std::unordered_map<node_t, node_t> preorder;
std::unordered_map<node_t, node_t> lowlink;
std::set<node_t> scc_found;
std::vector<node_t> scc_queue;
int i = 0;
node_dict_factory& nodes_list = G_.node;
for (node_dict_factory::iterator source = nodes_list.begin(); source != nodes_list.end(); source++) {
node_t source_id = source->first;
if (scc_found.find(source_id) == scc_found.end()) {
std::vector<node_t> que;
que.emplace_back(source_id);
while (!que.empty()) {
node_t v_id = que.back();
if (preorder.find(v_id) == preorder.end()) {
i += 1;
preorder[v_id] = i;
}
bool done = true;
adj_attr_dict_factory& v_neighbors = adj[v_id];
for (adj_attr_dict_factory::iterator w = v_neighbors.begin(); w != v_neighbors.end(); w++) {
node_t w_id = w->first;
if (preorder.find(w_id) == preorder.end()) {
que.emplace_back(w_id);
done = false;
break;
}
}
if (done) {
lowlink[v_id] = preorder[v_id];
for (adj_attr_dict_factory::iterator w = v_neighbors.begin(); w != v_neighbors.end(); w++) {
node_t w_id = w->first;
if (scc_found.find(w_id) == scc_found.end()) {
if (preorder[w_id] > preorder[v_id]) {
lowlink[v_id] = std::min(lowlink[v_id], lowlink[w_id]);
} else {
lowlink[v_id] = std::min(lowlink[v_id], preorder[w_id]);
}
}
}
que.pop_back();
if (lowlink[v_id] == preorder[v_id]) {
std::unordered_set<node_t> scc;
scc.emplace(v_id);
while (!scc_queue.empty() && (preorder[scc_queue.back()] > preorder[v_id])) {
node_t k = scc_queue.back();
scc_queue.pop_back();
scc.emplace(k);
}
py::set tmp_res;
for (std::unordered_set<node_t>::iterator z = scc.begin(); z != scc.end(); z++) {
scc_found.emplace(*z);
tmp_res.add(G_.id_to_node.attr("get")(*z));
}
res.append(tmp_res);
} else {
scc_queue.emplace_back(v_id);
}
}
}
}
}
return res;
}
@@ -0,0 +1,6 @@
#pragma once
#include "../../common/common.h"
py::object strongly_connected_components(py::object G);
py::object strongly_connected_components_iteration_impl(py::object G);