在无向BGL图中:是否可以最初获取边(u,v)==(v,u)作为(u,v)还是作为(v,u)添加信息?
背景:
我使用内部使用Boost Graph Library(BGL)的Pythons图形工具库创建了一个图形。
每个边缘都有一个“有向属性”,指向边缘的源和目标:(source_range, target_range)
。
我想执行 undirected 深度优先搜索以查找两个节点之间的所有路径。我正在使用图形工具get_all_paths()作为基础。我以一种遍历图取决于“有向属性”的方式更改了底层BGL实现。我让它适用于定向案例。但是,当我将图形切换为无向时,我遇到的问题是我不知道边的初始方向。因此,我不知道edge属性的顺序:
(source_range, target_range)
与(target_range, source_range)
这是我的DFS代码,其中提到了停止条件(// Check overlap
部分):
template <class Graph, class Yield, class VMap, class EMap>
void get_all_paths(size_t s, size_t t, size_t cutoff, VMap visited,
EMap startend, Yield& yield, Graph& g)
{
typedef typename graph_traits<Graph>::out_edge_iterator eiter_t;
typedef std::pair<eiter_t, eiter_t> item_t;
visited[s] = true; // set visited true for source node
// could also use refrences to startend property map here. meh...
uint8_t t_start_e1, t_end_e1, q_start_e1, q_end_e1;
uint8_t q_start_e2, q_end_e2, t_start_e2, t_end_e2;
int32_t startend_e1;
int32_t startend_e2;
typedef typename property_map<Graph, vertex_index_t>::type IndexMap;
IndexMap index = get(vertex_index, g);
vector<size_t> vs = {s}; // vector of indexes
vector<item_t> stack = {out_edges(s, g)}; // vector of edge_iterator pairs
while (!stack.empty())
{
std::cout << "Stack before check overlap: ";
for (uint8_t i=0; i<stack.size(); i++) {
std::cout << " (" << source(*stack[i].first, g) << "," << target(*stack[i].first, g) << ") ";
}
std::cout << "\n";
auto& pos = stack.back(); // last element in eiter vector
// End of path because of self loop or cutoff is reached
if (pos.first == pos.second || stack.size() > cutoff)
{
visited[vs.back()] = false; // revoke visited flag for last node
vs.pop_back();
stack.pop_back();
if (!stack.empty())
++stack.back().first; // increment first iterator
continue;
}
// Check overlap
if (stack.size() > 1)
{
auto& pos_prev = *(stack.rbegin() + 1); // second last eiter
startend_e1 = startend[*pos_prev.first];
startend_e2 = startend[*pos.first];
std::cout << "Checking Edges: (" << source(*pos_prev.first, g) << "," << target(*pos_prev.first, g) << ")";
std::cout << " (" << source(*pos.first, g) << "," << target(*pos.first, g) << "):";
// take apart 2x int32_t to 8x int8_t (memory optimization)
// Undirected case:If the edge was added
// as (u,v) and (v,u) was detected
// I need to swap q(uery) and t(arget) values here.
// --> How can I detect if (u,v) was initially added as (u,v)
// or (v, u)
q_start_e1 = startend_e1 & 0xFF;
q_end_e1 = (startend_e1 >> 8) & 0xFF;
t_start_e1 = (startend_e1 >> 16) & 0xFF;
t_end_e1 = (startend_e1 >> 24) & 0xFF;
q_start_e2 = startend_e2 & 0xFF;
q_end_e2 = (startend_e2 >> 8) & 0xFF;
t_start_e2 = (startend_e2 >> 16) & 0xFF;
t_end_e2 = (startend_e2 >> 24) & 0xFF;
if ((min(t_end_e1, q_end_e2) - max(t_start_e1, q_start_e2)) < 1)
{
std::cout << "Failed\n";
++pos.first;
std::cout << "Stack after check overlap: ";
for (uint8_t i=0; i<stack.size(); i++) {
std::cout << "(" << source(*stack[i].first, g) << "," << target(*stack[i].first, g) << ") ";
}
std::cout << "\n";
continue;
}
std::cout << "Passed\n";
}
auto v = target(*pos.first, g); // get target vertex
// reached target node
if (v == t)
{
vector<size_t> path = {s}; // path vector
for (auto& ei : stack)
path.push_back(target(*ei.first, g));
yield(wrap_vector_owned<size_t>(path)); // yield path
++pos.first; // increment eiter
}
else
{
//check if node was visited
if (!visited[v]) //not visited
{
visited[v] = true;
vs.push_back(v);
stack.push_back(out_edges(v, g));
}
else // visited
{
++pos.first;
}
}
}
};
谢谢您的帮助!
更新:
我针对我的问题提出了以下解决方法。我具有边(some_val_ref_u, some_val_ref_v)
的边属性(u,v)
。在无向图中,边(v,u)
仍将具有边属性(some_val_ref_u, some_val_ref_v)
。因此,我将some_val_ref_u
分配给v
,将some_val_ref_v
分配给u
,这是不正确的。在处理“反向边缘”时,我必须考虑顺序。
我想到的解决方案是在创建图形时根据v
和u
的边索引来动态设置顺序。
if edge_index[v] < edge_index[u]:
g.ep.myattr[g.edge(v,u)] = (some_val_ref_v, some_val_ref_u)
else:
g.ep.myattr[g.edge(v,u)] = (some_val_ref_u, some_val_ref_v)
因此,边缘属性元组的顺序取决于哪个边缘索引较小。因此,在遍历图形时,我可以通过比较顶点索引来确定edge属性的顺序。
这不会直接回答我的问题,但希望可以解决我的问题。
答案 0 :(得分:0)
您可以简单地迭代:
for (auto ed : boost::make_iterator_range(edges(g))) {
std::cout << "Added as " << ed << " (so " << source(ed, g) << "->" << target(ed, g) << ")\n";
}
这是由于邻接表存储每个节点的邻接表。
对于有向图,此循环实际上等效于 在做:
for (auto from : boost::make_iterator_range(vertices(g))) { for (auto to : boost::make_iterator_range(adjacent_vertices(from, g))) std::cout << "Added as " << from << "->" << to << "\n"; }
但是,对于无向图,这将列出所有重复的非自身边。
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <iostream>
void testcase(int from, int to) {
using namespace boost;
adjacency_list<vecS, vecS, undirectedS> g(2);
add_edge(from, to, g);
for (auto ed : boost::make_iterator_range(edges(g))) {
std::cout << "Added as " << ed << " (so " << source(ed, g) << "->" << target(ed, g) << ")\n";
}
}
int main() {
testcase(0, 1);
testcase(1, 0);
}
打印
Added as (0,1) (so 0->1)
Added as (1,0) (so 1->0)
答案 1 :(得分:0)
sehe的答案不正确-无法从任何边缘描述符中获取原始源顶点和目标顶点,如下所示:
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
int main() {
using namespace boost;
typedef adjacency_list<vecS, vecS, undirectedS> Graph;
Graph g(2);
add_edge(0, 1, g);
for (auto ed : make_iterator_range(edges(g))) {
std::cout << "Added as " << ed << " (so " << source(ed, g) << "->" << target(ed, g) << ")\n";
}
//edge (1,0) exists since the graph is undirected,
//yet source and target vertices are not the way they were originally specified
Graph::edge_descriptor ed = edge(1, 0, g).first;
std::cout << ed << " (so " << source(ed, g) << "->" << target(ed, g) << ')';
}
如上所述,一种解决方案是遍历所有边缘。
另一个更有效的方法是在顶点u的边缘(或相反方向)寻找顶点v:
#include <iostream>
#include <cassert>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
int main() {
using namespace boost;
typedef adjacency_list<vecS, vecS, undirectedS> Graph;
Graph g(2);
add_edge(0, 1, g);
Graph::EdgeContainer::const_iterator edge1 = std::find(g.out_edge_list(0).begin(), g.out_edge_list(0).end(), Graph::StoredEdge(1))->get_iter();
Graph::EdgeContainer::const_iterator edge2 = std::find(g.out_edge_list(1).begin(), g.out_edge_list(1).end(), Graph::StoredEdge(0))->get_iter();
assert(edge1 == edge2);
std::cout << source(*edge1, g) << "->" << target(*edge1, g);
}