nxpp
Header-only graph utilities on top of Boost Graph Library
Loading...
Searching...
No Matches
traversal.hpp
Go to the documentation of this file.
1#pragma once
2
11#include <boost/graph/breadth_first_search.hpp>
12#include <boost/graph/depth_first_search.hpp>
13
14#include "graph.hpp"
15
16namespace nxpp {
17
26class visitor {
27public:
28 template <typename... Args>
29 void examine_vertex(Args&&...) {}
30
31 template <typename... Args>
32 void tree_edge(Args&&...) {}
33
34 template <typename... Args>
35 void back_edge(Args&&...) {}
36};
37
38
39// Algorithms: Traversals
40
41template <typename GraphWrapper, typename Edge>
42class GenericBfsEdgeVisitor : public boost::default_bfs_visitor {
43public:
44 using NodeID = typename GraphWrapper::NodeType;
45
46 GenericBfsEdgeVisitor(std::vector<std::pair<NodeID, NodeID>>& edges, const GraphWrapper& graph_wrapper)
47 : tree_edges(edges), graph_wrapper(graph_wrapper) {}
48
49 template <typename G>
50 void tree_edge(Edge e, const G& g) {
51 NodeID u = graph_wrapper.get_node_id(boost::source(e, g));
52 NodeID v = graph_wrapper.get_node_id(boost::target(e, g));
53 tree_edges.emplace_back(u, v);
54 }
55private:
56 std::vector<std::pair<NodeID, NodeID>>& tree_edges;
57 const GraphWrapper& graph_wrapper;
58};
59
60template <typename GraphWrapper>
68[[deprecated("Use G.bfs_edges(start) instead.")]]
69auto bfs_edges(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
70 return G.bfs_edges(start);
71}
72
73template <typename GraphWrapper>
81[[deprecated("Use G.bfs_tree(start) instead.")]]
82auto bfs_tree(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
83 return G.bfs_tree(start);
84}
85
86template <typename GraphWrapper>
94[[deprecated("Use G.bfs_successors(start) instead.")]]
95auto bfs_successors(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
96 return G.bfs_successors(start);
97}
98
99template <typename GraphWrapper, typename Edge, typename OnVertex, typename OnTreeEdge>
100class GenericBfsVisitVisitor : public boost::default_bfs_visitor {
101public:
102 using NodeID = typename GraphWrapper::NodeType;
103
104 GenericBfsVisitVisitor(const GraphWrapper& graph_wrapper, OnVertex& on_vertex, OnTreeEdge& on_tree_edge)
105 : graph_wrapper(graph_wrapper), on_vertex(on_vertex), on_tree_edge(on_tree_edge) {}
106
107 template <typename G>
108 void examine_vertex(typename boost::graph_traits<G>::vertex_descriptor u, const G&) const {
109 on_vertex(graph_wrapper.get_node_id(u));
110 }
111
112 template <typename G>
113 void tree_edge(Edge e, const G& g) const {
114 on_tree_edge(graph_wrapper.get_node_id(boost::source(e, g)), graph_wrapper.get_node_id(boost::target(e, g)));
115 }
116
117private:
118 const GraphWrapper& graph_wrapper;
119 OnVertex& on_vertex;
120 OnTreeEdge& on_tree_edge;
121};
122
123template <typename Visitor, typename NodeID, typename GraphWrapper>
124void bfs_dispatch_examine_vertex(Visitor& visitor, const NodeID& u, const GraphWrapper& G) {
125 if constexpr (requires { visitor.examine_vertex(u, G); }) {
126 visitor.examine_vertex(u, G);
127 }
128}
129
130template <typename Visitor, typename NodeID, typename GraphWrapper>
131void bfs_dispatch_tree_edge(Visitor& visitor, const NodeID& u, const NodeID& v, const GraphWrapper& G) {
132 if constexpr (requires { visitor.tree_edge(u, v, G); }) {
133 visitor.tree_edge(u, v, G);
134 }
135}
136
137template <typename NodeID, typename Edge, typename GraphWrapper, typename Visitor>
138class GenericBfsObjectVisitor : public boost::default_bfs_visitor {
139public:
140 GenericBfsObjectVisitor(const GraphWrapper& graph_wrapper, Visitor& visitor)
141 : graph_wrapper(graph_wrapper), visitor(visitor) {}
142
143 template <typename G>
144 void examine_vertex(typename boost::graph_traits<G>::vertex_descriptor u, const G&) const {
145 bfs_dispatch_examine_vertex(visitor, graph_wrapper.get_node_id(u), graph_wrapper);
146 }
147
148 template <typename G>
149 void tree_edge(Edge e, const G& g) const {
150 bfs_dispatch_tree_edge(
151 visitor,
152 graph_wrapper.get_node_id(boost::source(e, g)),
153 graph_wrapper.get_node_id(boost::target(e, g)),
154 graph_wrapper
155 );
156 }
157
158private:
159 const GraphWrapper& graph_wrapper;
160 Visitor& visitor;
161};
162
163template <typename GraphWrapper, typename Visitor>
171[[deprecated("Use G.breadth_first_search(start, visitor) instead.")]]
172void breadth_first_search(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, Visitor& visitor) {
173 G.breadth_first_search(start, visitor);
174}
175
176template <typename GraphWrapper, typename OnVertex, typename OnTreeEdge>
185[[deprecated("Use G.bfs_visit(start, on_vertex, on_tree_edge) instead.")]]
186void bfs_visit(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, OnVertex&& on_vertex, OnTreeEdge&& on_tree_edge) {
187 G.bfs_visit(start, std::forward<OnVertex>(on_vertex), std::forward<OnTreeEdge>(on_tree_edge));
188}
189
190template <typename GraphWrapper, typename Edge>
191class GenericDfsEdgeVisitor : public boost::default_dfs_visitor {
192public:
193 using NodeID = typename GraphWrapper::NodeType;
194
195 GenericDfsEdgeVisitor(std::vector<std::pair<NodeID, NodeID>>& edges, const GraphWrapper& graph_wrapper)
196 : tree_edges(edges), graph_wrapper(graph_wrapper) {}
197
198 template <typename G>
199 void tree_edge(Edge e, const G& g) {
200 NodeID u = graph_wrapper.get_node_id(boost::source(e, g));
201 NodeID v = graph_wrapper.get_node_id(boost::target(e, g));
202 tree_edges.emplace_back(u, v);
203 }
204private:
205 std::vector<std::pair<NodeID, NodeID>>& tree_edges;
206 const GraphWrapper& graph_wrapper;
207};
208
209template <typename GraphWrapper>
217[[deprecated("Use G.dfs_edges(start) instead.")]]
218auto dfs_edges(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
219 return G.dfs_edges(start);
220}
221
222template <typename GraphWrapper>
230[[deprecated("Use G.dfs_tree(start) instead.")]]
231auto dfs_tree(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
232 return G.dfs_tree(start);
233}
234
235template <typename GraphWrapper>
243[[deprecated("Use G.dfs_predecessors(start) instead.")]]
244auto dfs_predecessors(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
245 return G.dfs_predecessors(start);
246}
247
248template <typename GraphWrapper>
256[[deprecated("Use G.dfs_successors(start) instead.")]]
257auto dfs_successors(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
258 return G.dfs_successors(start);
259}
260
261template <typename GraphWrapper, typename Edge, typename OnTreeEdge, typename OnBackEdge>
262class GenericDfsVisitVisitor : public boost::default_dfs_visitor {
263public:
264 GenericDfsVisitVisitor(const GraphWrapper& graph_wrapper, OnTreeEdge& on_tree_edge, OnBackEdge& on_back_edge)
265 : graph_wrapper(graph_wrapper), on_tree_edge(on_tree_edge), on_back_edge(on_back_edge) {}
266
267 template <typename G>
268 void tree_edge(Edge e, const G& g) const {
269 on_tree_edge(graph_wrapper.get_node_id(boost::source(e, g)), graph_wrapper.get_node_id(boost::target(e, g)));
270 }
271
272 template <typename G>
273 void back_edge(Edge e, const G& g) const {
274 on_back_edge(graph_wrapper.get_node_id(boost::source(e, g)), graph_wrapper.get_node_id(boost::target(e, g)));
275 }
276
277private:
278 const GraphWrapper& graph_wrapper;
279 OnTreeEdge& on_tree_edge;
280 OnBackEdge& on_back_edge;
281};
282
283template <typename Visitor, typename NodeID, typename GraphWrapper>
284void dfs_dispatch_tree_edge(Visitor& visitor, const NodeID& u, const NodeID& v, const GraphWrapper& G) {
285 if constexpr (requires { visitor.tree_edge(u, v, G); }) {
286 visitor.tree_edge(u, v, G);
287 }
288}
289
290template <typename Visitor, typename NodeID, typename GraphWrapper>
291void dfs_dispatch_back_edge(Visitor& visitor, const NodeID& u, const NodeID& v, const GraphWrapper& G) {
292 if constexpr (requires { visitor.back_edge(u, v, G); }) {
293 visitor.back_edge(u, v, G);
294 }
295}
296
297template <typename NodeID, typename Edge, typename GraphWrapper, typename Visitor>
298class GenericDfsObjectVisitor : public boost::default_dfs_visitor {
299public:
300 GenericDfsObjectVisitor(const GraphWrapper& graph_wrapper, Visitor& visitor)
301 : graph_wrapper(graph_wrapper), visitor(visitor) {}
302
303 template <typename G>
304 void tree_edge(Edge e, const G& g) const {
305 dfs_dispatch_tree_edge(
306 visitor,
307 graph_wrapper.get_node_id(boost::source(e, g)),
308 graph_wrapper.get_node_id(boost::target(e, g)),
309 graph_wrapper
310 );
311 }
312
313 template <typename G>
314 void back_edge(Edge e, const G& g) const {
315 dfs_dispatch_back_edge(
316 visitor,
317 graph_wrapper.get_node_id(boost::source(e, g)),
318 graph_wrapper.get_node_id(boost::target(e, g)),
319 graph_wrapper
320 );
321 }
322
323private:
324 const GraphWrapper& graph_wrapper;
325 Visitor& visitor;
326};
327
328template <typename GraphWrapper, typename Visitor>
336[[deprecated("Use G.depth_first_search(start, visitor) instead.")]]
337void depth_first_search(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, Visitor& visitor) {
338 G.depth_first_search(start, visitor);
339}
340
341template <typename GraphWrapper, typename OnTreeEdge, typename OnBackEdge>
350[[deprecated("Use G.dfs_visit(start, on_tree_edge, on_back_edge) instead.")]]
351void dfs_visit(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, OnTreeEdge&& on_tree_edge, OnBackEdge&& on_back_edge) {
352 G.dfs_visit(start, std::forward<OnTreeEdge>(on_tree_edge), std::forward<OnBackEdge>(on_back_edge));
353}
354
355template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
357 std::vector<std::pair<NodeID, NodeID>> edges;
358 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
359
360 if (!has_node(start)) {
361 throw std::runtime_error("Traversal failed: start node not found.");
362 }
363
364 const auto start_bgl = get_id_to_bgl_map().at(start);
366 boost::breadth_first_search(get_impl(), start_bgl, boost::visitor(vis));
367 return edges;
368}
369
370template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
373
374 if (!has_node(start)) {
375 throw std::runtime_error("Traversal failed: start node not found.");
376 }
377
378 tree.add_node(start);
379 for (const auto& [u, v] : bfs_edges(start)) {
380 tree.add_edge(u, v);
381 }
382 return tree;
383}
384
385template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
387 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
388 std::vector<std::optional<std::vector<NodeID>>> successors(boost::num_vertices(g));
389 for (const auto& [u, v] : bfs_edges(start)) {
390 const auto parent_index = get_vertex_index(get_id_to_bgl_map().at(u));
391 if (!successors[parent_index].has_value()) {
392 successors[parent_index] = std::vector<NodeID>{};
393 }
394 successors[parent_index]->push_back(v);
395 }
396 return build_sparse_node_indexed_result<std::vector<NodeID>>(successors);
397}
398
399template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
400template <typename Visitor>
402 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
403 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
404 const auto start_bgl = get_id_to_bgl_map().at(start);
405 std::vector<boost::default_color_type> color(boost::num_vertices(g));
407 boost::breadth_first_search(
408 get_impl(),
409 start_bgl,
410 boost::visitor(vis).color_map(boost::make_iterator_property_map(color.begin(), vertex_index_map))
411 );
412}
413
414template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
415template <typename OnVertex, typename OnTreeEdge>
416void Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>::bfs_visit(const NodeID& start, OnVertex&& on_vertex, OnTreeEdge&& on_tree_edge) const {
417 struct callback_visitor {
418 OnVertex& on_vertex;
419 OnTreeEdge& on_tree_edge;
420 void examine_vertex(const NodeID& u, const Graph&) { on_vertex(u); }
421 void tree_edge(const NodeID& u, const NodeID& v, const Graph&) { on_tree_edge(u, v); }
422 };
423 auto on_vertex_fn = std::forward<OnVertex>(on_vertex);
424 auto on_tree_edge_fn = std::forward<OnTreeEdge>(on_tree_edge);
425 callback_visitor visitor{on_vertex_fn, on_tree_edge_fn};
427}
428
429template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
431 std::vector<std::pair<NodeID, NodeID>> edges;
432 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
433
434 if (!has_node(start)) {
435 throw std::runtime_error("Traversal failed: start node not found.");
436 }
437
438 const auto start_bgl = get_id_to_bgl_map().at(start);
440 std::vector<boost::default_color_type> color(boost::num_vertices(g));
441 boost::depth_first_search(
442 get_impl(),
443 boost::root_vertex(start_bgl)
444 .visitor(vis)
445 .color_map(boost::make_iterator_property_map(color.begin(), vertex_index_map))
446 );
447 return edges;
448}
449
450template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
453
454 if (!has_node(start)) {
455 throw std::runtime_error("Traversal failed: start node not found.");
456 }
457
458 tree.add_node(start);
459 for (const auto& [u, v] : dfs_edges(start)) {
460 tree.add_edge(u, v);
461 }
462 return tree;
463}
464
465template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
467 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
468 std::vector<std::optional<NodeID>> predecessors(boost::num_vertices(g));
469 for (const auto& [u, v] : dfs_edges(start)) {
470 predecessors[get_vertex_index(get_id_to_bgl_map().at(v))] = u;
471 }
472 return build_sparse_node_indexed_result<NodeID>(predecessors);
473}
474
475template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
477 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
478 std::vector<std::optional<std::vector<NodeID>>> successors(boost::num_vertices(g));
479 for (const auto& [u, v] : dfs_edges(start)) {
480 const auto parent_index = get_vertex_index(get_id_to_bgl_map().at(u));
481 if (!successors[parent_index].has_value()) {
482 successors[parent_index] = std::vector<NodeID>{};
483 }
484 successors[parent_index]->push_back(v);
485 }
486 return build_sparse_node_indexed_result<std::vector<NodeID>>(successors);
487}
488
489template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
490template <typename Visitor>
492 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
493 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
494 const auto start_bgl = get_id_to_bgl_map().at(start);
495 std::vector<boost::default_color_type> color(boost::num_vertices(g));
497 boost::depth_first_search(
498 get_impl(),
499 boost::root_vertex(start_bgl)
500 .visitor(vis)
501 .color_map(boost::make_iterator_property_map(color.begin(), vertex_index_map))
502 );
503}
504
505template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
506template <typename OnTreeEdge, typename OnBackEdge>
507void Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>::dfs_visit(const NodeID& start, OnTreeEdge&& on_tree_edge, OnBackEdge&& on_back_edge) const {
508 struct callback_visitor {
509 OnTreeEdge& on_tree_edge;
510 OnBackEdge& on_back_edge;
511 void tree_edge(const NodeID& u, const NodeID& v, const Graph&) { on_tree_edge(u, v); }
512 void back_edge(const NodeID& u, const NodeID& v, const Graph&) { on_back_edge(u, v); }
513 };
514 auto on_tree_edge_fn = std::forward<OnTreeEdge>(on_tree_edge);
515 auto on_back_edge_fn = std::forward<OnBackEdge>(on_back_edge);
516 callback_visitor visitor{on_tree_edge_fn, on_back_edge_fn};
518}
519
520} // namespace nxpp
Definition traversal.hpp:42
Definition traversal.hpp:138
Definition traversal.hpp:100
Definition traversal.hpp:191
Definition traversal.hpp:298
Definition traversal.hpp:262
Graph wrapper around Boost Graph Library with Python-inspired helpers.
Definition graph.hpp:272
auto dfs_predecessors(const NodeID &start) const
Returns the DFS predecessor assigned to each discovered node.
Definition traversal.hpp:466
auto bfs_tree(const NodeID &start) const
Materializes the breadth-first-search tree rooted at start.
Definition traversal.hpp:371
void bfs_visit(const NodeID &start, OnVertex &&on_vertex, OnTreeEdge &&on_tree_edge) const
Runs breadth-first search with lightweight callback hooks.
Definition traversal.hpp:416
void dfs_visit(const NodeID &start, OnTreeEdge &&on_tree_edge, OnBackEdge &&on_back_edge) const
Runs depth-first search with lightweight callback hooks.
Definition traversal.hpp:507
auto dfs_successors(const NodeID &start) const
Groups DFS tree children by their discovered parent.
Definition traversal.hpp:476
auto bfs_edges(const NodeID &start) const
Returns the tree edges discovered by breadth-first search.
Definition traversal.hpp:356
void depth_first_search(const NodeID &start, Visitor &visitor) const
Runs depth-first search with an object-style visitor.
Definition traversal.hpp:491
void add_node(const NodeID &id)
Ensures that a node with the given ID exists in the graph.
Definition graph.hpp:507
void breadth_first_search(const NodeID &start, Visitor &visitor) const
Runs breadth-first search with an object-style visitor.
Definition traversal.hpp:401
auto dfs_edges(const NodeID &start) const
Returns the tree edges discovered by depth-first search.
Definition traversal.hpp:430
auto bfs_successors(const NodeID &start) const
Groups BFS tree children by their discovered parent.
Definition traversal.hpp:386
auto dfs_tree(const NodeID &start) const
Materializes the depth-first-search tree rooted at start.
Definition traversal.hpp:451
Minimal visitor interface for wrapper-level traversal callbacks.
Definition traversal.hpp:26
Core graph wrapper, proxy surface, and public alias presets.
auto bfs_successors(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.bfs_successors(start).
Definition traversal.hpp:95
void depth_first_search(const GraphWrapper &G, const typename GraphWrapper::NodeType &start, Visitor &visitor)
Deprecated free-function alias for G.depth_first_search(start, visitor).
Definition traversal.hpp:337
void dfs_visit(const GraphWrapper &G, const typename GraphWrapper::NodeType &start, OnTreeEdge &&on_tree_edge, OnBackEdge &&on_back_edge)
Deprecated free-function alias for G.dfs_visit(start, on_tree_edge, on_back_edge).
Definition traversal.hpp:351
auto dfs_successors(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_successors(start).
Definition traversal.hpp:257
void breadth_first_search(const GraphWrapper &G, const typename GraphWrapper::NodeType &start, Visitor &visitor)
Deprecated free-function alias for G.breadth_first_search(start, visitor).
Definition traversal.hpp:172
auto dfs_tree(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_tree(start).
Definition traversal.hpp:231
auto bfs_edges(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.bfs_edges(start).
Definition traversal.hpp:69
auto dfs_predecessors(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_predecessors(start).
Definition traversal.hpp:244
auto bfs_tree(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.bfs_tree(start).
Definition traversal.hpp:82
auto dfs_edges(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_edges(start).
Definition traversal.hpp:218
void bfs_visit(const GraphWrapper &G, const typename GraphWrapper::NodeType &start, OnVertex &&on_vertex, OnTreeEdge &&on_tree_edge)
Deprecated free-function alias for G.bfs_visit(start, on_vertex, on_tree_edge).
Definition traversal.hpp:186