in include/WeakPartialOrdering.h [299:374]
void construct_auxilary(const NodeId& root) {
// It uses disjoint-sets data structure.
typedef std::unordered_map<uint32_t, std::size_t> rank_t;
typedef std::unordered_map<uint32_t, uint32_t> parent_t;
rank_t rank_map;
parent_t parent_map;
typedef boost::associative_property_map<rank_t> r_pmap_t;
r_pmap_t r_pmap(rank_map);
typedef boost::associative_property_map<parent_t> p_pmap_t;
p_pmap_t p_pmap(parent_map);
boost::disjoint_sets<r_pmap_t, p_pmap_t> dsets(r_pmap, p_pmap);
std::unordered_map<uint32_t, uint32_t> ancestor;
std::stack<std::tuple<NodeId, bool, uint32_t>> stack;
std::unordered_map<uint32_t, bool> black;
stack.push(std::make_tuple(root, false, 0));
while (!stack.empty()) {
// Iterative DFS.
auto& stack_top = stack.top();
auto vertex_ref = std::get<0>(stack_top);
auto finished = std::get<1>(stack_top);
auto pred = std::get<2>(stack_top);
stack.pop();
if (finished) {
// DFS is done with this vertex.
// Set the post DFN.
m_post_dfn[vertex_ref] = m_next_post_dfn++;
auto vertex = get_dfn(vertex_ref);
// Mark visited.
black[vertex] = true;
dsets.union_set(vertex, pred);
ancestor[dsets.find_set(pred)] = pred;
} else {
if (get_dfn(vertex_ref) !=
0 /* means that the vertex is already discovered. */) {
// A forward edge.
// Forward edges can be ignored, as they are redundant.
continue;
}
// New vertex is discovered.
auto vertex = m_next_dfn++;
push_ref(vertex_ref);
set_dfn(vertex_ref, vertex);
dsets.make_set(vertex);
ancestor[vertex] = vertex;
// This will be popped after all its successors are finished.
stack.push(std::make_tuple(vertex_ref, true, pred));
auto successors = m_successors(vertex_ref);
// Successors vector is reversed to match the order with WTO.
for (auto rit = successors.rbegin(); rit != successors.rend(); ++rit) {
auto succ = get_dfn(*rit);
if (succ == 0 /* 0 means that vertex is undiscovered. */) {
// Newly discovered vertex. Search continues.
stack.push(std::make_tuple(*rit, false, vertex));
} else if (black[succ]) {
// A cross edge.
auto lca = ancestor[dsets.find_set(succ)];
m_cross_fwds[lca].emplace_back(vertex, succ);
} else {
// A back edge.
m_back_preds[succ].push_back(vertex);
}
}
if (pred != 0) {
// A tree edge.
m_non_back_preds[vertex].push_back(pred);
}
}
}
}