In an undirected BGL graph: Can I get the information whether an edge (u,v) == (v,u) was initially added as (u,v) or as (v,u)?
Background:
I created a graph using Pythons graph-tool library which internally uses Boost Graph Library (BGL).
Each edge has a "directed attribute" referring to source and target of the edge: (source_range, target_range)
.
I want to perform an undirected Depth-First search to find all paths between two nodes. I'm using graph-tools get_all_paths() as a basis. I altered the underlying BGL implementation in a way that traversal of the graph depends on the "directed attribute". I got it working for the directed case. However when I switch the graph to undirected I have the problem that I don't know the initial direction of an edge. Thus I don't know the ordering of the edge attribute:
(source_range, target_range)
vs (target_range, source_range)
Here is my DFS code with the mentioned stop criterion (// Check overlap
part):
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;
}
}
}
};
Thank you for your help!
Update:
I came up with the following workaround for my problem. I have an edge property (some_val_ref_u, some_val_ref_v)
of the edge (u,v)
. In an undirected graph the edge (v,u)
will still have the edge property (some_val_ref_u, some_val_ref_v)
. Thus I would assign some_val_ref_u
to v
and some_val_ref_v
to u
, which is not correct. I have to take the order into account when dealing with a "reverse edge".
The solution I came up with is to set the order dynamically when creating the graph depending on the edge index of v
and 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)
So the order of the edge property tuple depends on which edge index is smaller. Consequently, when traversing the graph, I can decide the order of the edge attribute by comparing the vertex indices.
This does not directly answer my question but hopefully will be a workaround for my problem.