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 <iterator>
15#include <memory>
16#include <optional>
17#include <queue>
18#include <vector>
19
20#include "graph.hpp"
21
22namespace nxpp {
23
24namespace detail {
25
26enum class traversal_order {
27 bfs,
28 dfs
29};
30
31template <typename GraphWrapper, traversal_order Order>
33public:
34 using NodeID = typename GraphWrapper::NodeType;
35 using value_type = std::pair<NodeID, NodeID>;
36
37 traversal_edges_view(const GraphWrapper& graph, const NodeID& start) : graph(&graph), start(start) {}
38
39 class iterator {
40 public:
41 using iterator_category = std::input_iterator_tag;
42 using value_type = traversal_edges_view::value_type;
43 using difference_type = std::ptrdiff_t;
44 using reference = const value_type&;
45
46 iterator() = default;
47
48 iterator(const GraphWrapper& graph, const NodeID& start)
49 : state(std::make_shared<traversal_state>(graph, start)) {
50 advance();
51 }
52
53 reference operator*() const {
54 return *state->current;
55 }
56
57 const value_type* operator->() const {
58 return &*state->current;
59 }
60
61 iterator& operator++() {
62 advance();
63 return *this;
64 }
65
66 void operator++(int) {
67 ++(*this);
68 }
69
70 friend bool operator==(const iterator& it, std::default_sentinel_t) {
71 return !it.state || it.state->done;
72 }
73
74 friend bool operator==(std::default_sentinel_t sentinel, const iterator& it) {
75 return it == sentinel;
76 }
77
78 private:
79 using GraphType = typename GraphWrapper::GraphType;
80 using VertexDesc = typename GraphWrapper::VertexDesc;
81 using OutEdgeIterator = typename boost::graph_traits<GraphType>::out_edge_iterator;
82
83 struct edge_cursor {
84 VertexDesc vertex;
85 OutEdgeIterator current;
86 OutEdgeIterator end;
87 };
88
89 struct traversal_state {
90 traversal_state(const GraphWrapper& graph, const NodeID& start)
91 : graph(&graph),
92 colors(boost::num_vertices(graph.get_impl()), boost::white_color),
93 current(std::nullopt),
94 done(false) {
95 const auto start_vertex = graph.get_id_to_bgl_map().at(start);
96 colors[graph.get_vertex_index(start_vertex)] = boost::gray_color;
97 if constexpr (Order == traversal_order::bfs) {
98 bfs_queue.push(start_vertex);
99 } else {
100 push_dfs_vertex(start_vertex);
101 }
102 }
103
104 void push_dfs_vertex(VertexDesc vertex) {
105 auto [edge_it, edge_end] = boost::out_edges(vertex, graph->get_impl());
106 dfs_stack.push_back(edge_cursor{vertex, edge_it, edge_end});
107 }
108
109 const GraphWrapper* graph;
110 std::vector<boost::default_color_type> colors;
111 std::queue<VertexDesc> bfs_queue;
112 std::optional<edge_cursor> bfs_cursor;
113 std::vector<edge_cursor> dfs_stack;
114 std::optional<value_type> current;
115 bool done;
116 };
117
118 void advance() {
119 if (!state || state->done) {
120 return;
121 }
122
123 state->current.reset();
124 if constexpr (Order == traversal_order::bfs) {
125 advance_bfs();
126 } else {
127 advance_dfs();
128 }
129 }
130
131 void advance_bfs() {
132 while (!state->bfs_queue.empty()) {
133 if (!state->bfs_cursor.has_value()) {
134 const auto vertex = state->bfs_queue.front();
135 auto [edge_it, edge_end] = boost::out_edges(vertex, state->graph->get_impl());
136 state->bfs_cursor = edge_cursor{vertex, edge_it, edge_end};
137 }
138
139 while (state->bfs_cursor->current != state->bfs_cursor->end) {
140 const auto edge = *state->bfs_cursor->current;
141 ++state->bfs_cursor->current;
142 const auto child = boost::target(edge, state->graph->get_impl());
143 const auto child_index = state->graph->get_vertex_index(child);
144 if (state->colors[child_index] == boost::white_color) {
145 state->colors[child_index] = boost::gray_color;
146 state->bfs_queue.push(child);
147 state->current = value_type{
148 state->graph->get_node_id(state->bfs_cursor->vertex),
149 state->graph->get_node_id(child)
150 };
151 return;
152 }
153 }
154
155 state->colors[state->graph->get_vertex_index(state->bfs_cursor->vertex)] = boost::black_color;
156 state->bfs_queue.pop();
157 state->bfs_cursor.reset();
158 }
159
160 state->done = true;
161 }
162
163 void advance_dfs() {
164 while (!state->dfs_stack.empty()) {
165 auto& cursor = state->dfs_stack.back();
166 while (cursor.current != cursor.end) {
167 const auto edge = *cursor.current;
168 ++cursor.current;
169 const auto child = boost::target(edge, state->graph->get_impl());
170 const auto child_index = state->graph->get_vertex_index(child);
171 if (state->colors[child_index] == boost::white_color) {
172 state->colors[child_index] = boost::gray_color;
173 state->current = value_type{
174 state->graph->get_node_id(cursor.vertex),
175 state->graph->get_node_id(child)
176 };
177 state->push_dfs_vertex(child);
178 return;
179 }
180 }
181
182 state->colors[state->graph->get_vertex_index(cursor.vertex)] = boost::black_color;
183 state->dfs_stack.pop_back();
184 }
185
186 state->done = true;
187 }
188
189 std::shared_ptr<traversal_state> state;
190 };
191
192 iterator begin() const {
193 return iterator(*graph, start);
194 }
195
196 std::default_sentinel_t end() const {
197 return {};
198 }
199
200private:
201 const GraphWrapper* graph;
202 NodeID start;
203};
204
205template <typename NodeID, typename EdgeWeight, bool Directed, typename EdgeRange>
206Graph<NodeID, EdgeWeight, Directed> build_tree_from_edges(const NodeID& root, const EdgeRange& edges) {
207 Graph<NodeID, EdgeWeight, Directed> tree;
208 tree.add_node(root);
209 for (const auto& [u, v] : edges) {
210 tree.add_edge(u, v);
211 }
212 return tree;
213}
214
215} // namespace detail
216
225class visitor {
226public:
227 template <typename... Args>
228 void examine_vertex(Args&&...) {}
229
230 template <typename... Args>
231 void tree_edge(Args&&...) {}
232
233 template <typename... Args>
234 void back_edge(Args&&...) {}
235};
236
237
238// Algorithms: Traversals
239
240template <typename GraphWrapper, typename Edge>
241class GenericBfsEdgeVisitor : public boost::default_bfs_visitor {
242public:
243 using NodeID = typename GraphWrapper::NodeType;
244
245 GenericBfsEdgeVisitor(std::vector<std::pair<NodeID, NodeID>>& edges, const GraphWrapper& graph_wrapper)
246 : tree_edges(edges), graph_wrapper(graph_wrapper) {}
247
248 template <typename G>
249 void tree_edge(Edge e, const G& g) {
250 NodeID u = graph_wrapper.get_node_id(boost::source(e, g));
251 NodeID v = graph_wrapper.get_node_id(boost::target(e, g));
252 tree_edges.emplace_back(u, v);
253 }
254private:
255 std::vector<std::pair<NodeID, NodeID>>& tree_edges;
256 const GraphWrapper& graph_wrapper;
257};
258
259template <typename GraphWrapper>
267[[deprecated("Use G.bfs_edges(start) instead.")]]
268auto bfs_edges(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
269 return G.bfs_edges(start);
270}
271
272template <typename GraphWrapper>
280[[deprecated("Use G.bfs_tree(start) instead.")]]
281auto bfs_tree(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
282 return G.bfs_tree(start);
283}
284
285template <typename GraphWrapper>
293[[deprecated("Use G.bfs_successors(start) instead.")]]
294auto bfs_successors(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
295 return G.bfs_successors(start);
296}
297
298template <typename GraphWrapper, typename Edge, typename OnVertex, typename OnTreeEdge>
299class GenericBfsVisitVisitor : public boost::default_bfs_visitor {
300public:
301 using NodeID = typename GraphWrapper::NodeType;
302
303 GenericBfsVisitVisitor(const GraphWrapper& graph_wrapper, OnVertex& on_vertex, OnTreeEdge& on_tree_edge)
304 : graph_wrapper(graph_wrapper), on_vertex(on_vertex), on_tree_edge(on_tree_edge) {}
305
306 template <typename G>
307 void examine_vertex(typename boost::graph_traits<G>::vertex_descriptor u, const G&) const {
308 on_vertex(graph_wrapper.get_node_id(u));
309 }
310
311 template <typename G>
312 void tree_edge(Edge e, const G& g) const {
313 on_tree_edge(graph_wrapper.get_node_id(boost::source(e, g)), graph_wrapper.get_node_id(boost::target(e, g)));
314 }
315
316private:
317 const GraphWrapper& graph_wrapper;
318 OnVertex& on_vertex;
319 OnTreeEdge& on_tree_edge;
320};
321
322template <typename Visitor, typename NodeID, typename GraphWrapper>
323void bfs_dispatch_examine_vertex(Visitor& visitor, const NodeID& u, const GraphWrapper& G) {
324 if constexpr (requires { visitor.examine_vertex(u, G); }) {
325 visitor.examine_vertex(u, G);
326 }
327}
328
329template <typename Visitor, typename NodeID, typename GraphWrapper>
330void bfs_dispatch_tree_edge(Visitor& visitor, const NodeID& u, const NodeID& v, const GraphWrapper& G) {
331 if constexpr (requires { visitor.tree_edge(u, v, G); }) {
332 visitor.tree_edge(u, v, G);
333 }
334}
335
336template <typename NodeID, typename Edge, typename GraphWrapper, typename Visitor>
337class GenericBfsObjectVisitor : public boost::default_bfs_visitor {
338public:
339 GenericBfsObjectVisitor(const GraphWrapper& graph_wrapper, Visitor& visitor)
340 : graph_wrapper(graph_wrapper), visitor(visitor) {}
341
342 template <typename G>
343 void examine_vertex(typename boost::graph_traits<G>::vertex_descriptor u, const G&) const {
344 bfs_dispatch_examine_vertex(visitor, graph_wrapper.get_node_id(u), graph_wrapper);
345 }
346
347 template <typename G>
348 void tree_edge(Edge e, const G& g) const {
349 bfs_dispatch_tree_edge(
350 visitor,
351 graph_wrapper.get_node_id(boost::source(e, g)),
352 graph_wrapper.get_node_id(boost::target(e, g)),
353 graph_wrapper
354 );
355 }
356
357private:
358 const GraphWrapper& graph_wrapper;
359 Visitor& visitor;
360};
361
362template <typename GraphWrapper, typename Visitor>
370[[deprecated("Use G.breadth_first_search(start, visitor) instead.")]]
371void breadth_first_search(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, Visitor& visitor) {
372 G.breadth_first_search(start, visitor);
373}
374
375template <typename GraphWrapper, typename OnVertex, typename OnTreeEdge>
384[[deprecated("Use G.bfs_visit(start, on_vertex, on_tree_edge) instead.")]]
385void bfs_visit(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, OnVertex&& on_vertex, OnTreeEdge&& on_tree_edge) {
386 G.bfs_visit(start, std::forward<OnVertex>(on_vertex), std::forward<OnTreeEdge>(on_tree_edge));
387}
388
389template <typename GraphWrapper, typename Edge>
390class GenericDfsEdgeVisitor : public boost::default_dfs_visitor {
391public:
392 using NodeID = typename GraphWrapper::NodeType;
393
394 GenericDfsEdgeVisitor(std::vector<std::pair<NodeID, NodeID>>& edges, const GraphWrapper& graph_wrapper)
395 : tree_edges(edges), graph_wrapper(graph_wrapper) {}
396
397 template <typename G>
398 void tree_edge(Edge e, const G& g) {
399 NodeID u = graph_wrapper.get_node_id(boost::source(e, g));
400 NodeID v = graph_wrapper.get_node_id(boost::target(e, g));
401 tree_edges.emplace_back(u, v);
402 }
403private:
404 std::vector<std::pair<NodeID, NodeID>>& tree_edges;
405 const GraphWrapper& graph_wrapper;
406};
407
408template <typename GraphWrapper>
416[[deprecated("Use G.dfs_edges(start) instead.")]]
417auto dfs_edges(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
418 return G.dfs_edges(start);
419}
420
421template <typename GraphWrapper>
429[[deprecated("Use G.dfs_tree(start) instead.")]]
430auto dfs_tree(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
431 return G.dfs_tree(start);
432}
433
434template <typename GraphWrapper>
442[[deprecated("Use G.dfs_predecessors(start) instead.")]]
443auto dfs_predecessors(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
444 return G.dfs_predecessors(start);
445}
446
447template <typename GraphWrapper>
455[[deprecated("Use G.dfs_successors(start) instead.")]]
456auto dfs_successors(const GraphWrapper& G, const typename GraphWrapper::NodeType& start) {
457 return G.dfs_successors(start);
458}
459
460template <typename GraphWrapper, typename Edge, typename OnTreeEdge, typename OnBackEdge>
461class GenericDfsVisitVisitor : public boost::default_dfs_visitor {
462public:
463 GenericDfsVisitVisitor(const GraphWrapper& graph_wrapper, OnTreeEdge& on_tree_edge, OnBackEdge& on_back_edge)
464 : graph_wrapper(graph_wrapper), on_tree_edge(on_tree_edge), on_back_edge(on_back_edge) {}
465
466 template <typename G>
467 void tree_edge(Edge e, const G& g) const {
468 on_tree_edge(graph_wrapper.get_node_id(boost::source(e, g)), graph_wrapper.get_node_id(boost::target(e, g)));
469 }
470
471 template <typename G>
472 void back_edge(Edge e, const G& g) const {
473 on_back_edge(graph_wrapper.get_node_id(boost::source(e, g)), graph_wrapper.get_node_id(boost::target(e, g)));
474 }
475
476private:
477 const GraphWrapper& graph_wrapper;
478 OnTreeEdge& on_tree_edge;
479 OnBackEdge& on_back_edge;
480};
481
482template <typename Visitor, typename NodeID, typename GraphWrapper>
483void dfs_dispatch_tree_edge(Visitor& visitor, const NodeID& u, const NodeID& v, const GraphWrapper& G) {
484 if constexpr (requires { visitor.tree_edge(u, v, G); }) {
485 visitor.tree_edge(u, v, G);
486 }
487}
488
489template <typename Visitor, typename NodeID, typename GraphWrapper>
490void dfs_dispatch_back_edge(Visitor& visitor, const NodeID& u, const NodeID& v, const GraphWrapper& G) {
491 if constexpr (requires { visitor.back_edge(u, v, G); }) {
492 visitor.back_edge(u, v, G);
493 }
494}
495
496template <typename NodeID, typename Edge, typename GraphWrapper, typename Visitor>
497class GenericDfsObjectVisitor : public boost::default_dfs_visitor {
498public:
499 GenericDfsObjectVisitor(const GraphWrapper& graph_wrapper, Visitor& visitor)
500 : graph_wrapper(graph_wrapper), visitor(visitor) {}
501
502 template <typename G>
503 void tree_edge(Edge e, const G& g) const {
504 dfs_dispatch_tree_edge(
505 visitor,
506 graph_wrapper.get_node_id(boost::source(e, g)),
507 graph_wrapper.get_node_id(boost::target(e, g)),
508 graph_wrapper
509 );
510 }
511
512 template <typename G>
513 void back_edge(Edge e, const G& g) const {
514 dfs_dispatch_back_edge(
515 visitor,
516 graph_wrapper.get_node_id(boost::source(e, g)),
517 graph_wrapper.get_node_id(boost::target(e, g)),
518 graph_wrapper
519 );
520 }
521
522private:
523 const GraphWrapper& graph_wrapper;
524 Visitor& visitor;
525};
526
527template <typename GraphWrapper, typename Visitor>
535[[deprecated("Use G.depth_first_search(start, visitor) instead.")]]
536void depth_first_search(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, Visitor& visitor) {
537 G.depth_first_search(start, visitor);
538}
539
540template <typename GraphWrapper, typename OnTreeEdge, typename OnBackEdge>
549[[deprecated("Use G.dfs_visit(start, on_tree_edge, on_back_edge) instead.")]]
550void dfs_visit(const GraphWrapper& G, const typename GraphWrapper::NodeType& start, OnTreeEdge&& on_tree_edge, OnBackEdge&& on_back_edge) {
551 G.dfs_visit(start, std::forward<OnTreeEdge>(on_tree_edge), std::forward<OnBackEdge>(on_back_edge));
552}
553
554template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
556 std::vector<std::pair<NodeID, NodeID>> edges;
557 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
558
559 if (!has_node(start)) {
560 throw std::runtime_error("Traversal failed: start node not found.");
561 }
562
563 const auto start_bgl = get_id_to_bgl_map().at(start);
565 boost::breadth_first_search(get_impl(), start_bgl, boost::visitor(vis));
566 return edges;
567}
568
569template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
571 if (!has_node(start)) {
572 throw std::runtime_error("Traversal failed: start node not found.");
573 }
574
576}
577
578template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
580 if (!has_node(start)) {
581 throw std::runtime_error("Traversal failed: start node not found.");
582 }
583
584 return detail::build_tree_from_edges<NodeID, EdgeWeight, Directed>(start, bfs_edges(start));
585}
586
587template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
589 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
590 std::vector<std::optional<std::vector<NodeID>>> successors(boost::num_vertices(g));
591 for (const auto& [u, v] : bfs_edges(start)) {
592 const auto parent_index = get_vertex_index(get_id_to_bgl_map().at(u));
593 if (!successors[parent_index].has_value()) {
594 successors[parent_index] = std::vector<NodeID>{};
595 }
596 successors[parent_index]->push_back(v);
597 }
598 return build_sparse_node_indexed_result<std::vector<NodeID>>(successors);
599}
600
601template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
602template <typename Visitor>
604 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
605 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
606 const auto start_bgl = get_id_to_bgl_map().at(start);
607 std::vector<boost::default_color_type> color(boost::num_vertices(g));
609 boost::breadth_first_search(
610 get_impl(),
611 start_bgl,
612 boost::visitor(vis).color_map(boost::make_iterator_property_map(color.begin(), vertex_index_map))
613 );
614}
615
616template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
617template <typename OnVertex, typename OnTreeEdge>
618void Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>::bfs_visit(const NodeID& start, OnVertex&& on_vertex, OnTreeEdge&& on_tree_edge) const {
619 struct callback_visitor {
620 OnVertex& on_vertex;
621 OnTreeEdge& on_tree_edge;
622 void examine_vertex(const NodeID& u, const Graph&) { on_vertex(u); }
623 void tree_edge(const NodeID& u, const NodeID& v, const Graph&) { on_tree_edge(u, v); }
624 };
625 auto on_vertex_fn = std::forward<OnVertex>(on_vertex);
626 auto on_tree_edge_fn = std::forward<OnTreeEdge>(on_tree_edge);
627 callback_visitor visitor{on_vertex_fn, on_tree_edge_fn};
629}
630
631template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
633 std::vector<std::pair<NodeID, NodeID>> edges;
634 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
635
636 if (!has_node(start)) {
637 throw std::runtime_error("Traversal failed: start node not found.");
638 }
639
640 const auto start_bgl = get_id_to_bgl_map().at(start);
642 std::vector<boost::default_color_type> color(boost::num_vertices(g));
643 boost::depth_first_visit(
644 get_impl(),
645 start_bgl,
646 vis,
647 boost::make_iterator_property_map(color.begin(), vertex_index_map)
648 );
649 return edges;
650}
651
652template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
654 if (!has_node(start)) {
655 throw std::runtime_error("Traversal failed: start node not found.");
656 }
657
659}
660
661template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
663 if (!has_node(start)) {
664 throw std::runtime_error("Traversal failed: start node not found.");
665 }
666
667 return detail::build_tree_from_edges<NodeID, EdgeWeight, Directed>(start, dfs_edges(start));
668}
669
670template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
672 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
673 std::vector<std::optional<NodeID>> predecessors(boost::num_vertices(g));
674 for (const auto& [u, v] : dfs_edges(start)) {
675 predecessors[get_vertex_index(get_id_to_bgl_map().at(v))] = u;
676 }
677 return build_sparse_node_indexed_result<NodeID>(predecessors);
678}
679
680template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
682 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
683 std::vector<std::optional<std::vector<NodeID>>> successors(boost::num_vertices(g));
684 for (const auto& [u, v] : dfs_edges(start)) {
685 const auto parent_index = get_vertex_index(get_id_to_bgl_map().at(u));
686 if (!successors[parent_index].has_value()) {
687 successors[parent_index] = std::vector<NodeID>{};
688 }
689 successors[parent_index]->push_back(v);
690 }
691 return build_sparse_node_indexed_result<std::vector<NodeID>>(successors);
692}
693
694template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
695template <typename Visitor>
697 using EdgeType = typename boost::graph_traits<GraphType>::edge_descriptor;
698 if (!has_node(start)) throw std::runtime_error("Traversal failed: start node not found.");
699 const auto start_bgl = get_id_to_bgl_map().at(start);
700 std::vector<boost::default_color_type> color(boost::num_vertices(g));
702 boost::depth_first_visit(
703 get_impl(),
704 start_bgl,
705 vis,
706 boost::make_iterator_property_map(color.begin(), vertex_index_map)
707 );
708}
709
710template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
711template <typename OnTreeEdge, typename OnBackEdge>
712void Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>::dfs_visit(const NodeID& start, OnTreeEdge&& on_tree_edge, OnBackEdge&& on_back_edge) const {
713 struct callback_visitor {
714 OnTreeEdge& on_tree_edge;
715 OnBackEdge& on_back_edge;
716 void tree_edge(const NodeID& u, const NodeID& v, const Graph&) { on_tree_edge(u, v); }
717 void back_edge(const NodeID& u, const NodeID& v, const Graph&) { on_back_edge(u, v); }
718 };
719 auto on_tree_edge_fn = std::forward<OnTreeEdge>(on_tree_edge);
720 auto on_back_edge_fn = std::forward<OnBackEdge>(on_back_edge);
721 callback_visitor visitor{on_tree_edge_fn, on_back_edge_fn};
723}
724
725} // namespace nxpp
Definition traversal.hpp:241
Definition traversal.hpp:337
Definition traversal.hpp:299
Definition traversal.hpp:390
Definition traversal.hpp:497
Definition traversal.hpp:461
Graph wrapper around Boost Graph Library with Python-inspired helpers.
Definition graph.hpp:288
auto dfs_predecessors(const NodeID &start) const
Returns the DFS predecessor assigned to each discovered node.
Definition traversal.hpp:671
auto bfs_tree(const NodeID &start) const
Materializes the breadth-first-search tree rooted at start.
Definition traversal.hpp:579
auto bfs_edges_view(const NodeID &start) const
Returns a lazy input range over breadth-first-search tree edges.
Definition traversal.hpp:570
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:618
auto dfs_edges_view(const NodeID &start) const
Returns a lazy input range over depth-first-search tree edges.
Definition traversal.hpp:653
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:712
auto dfs_successors(const NodeID &start) const
Groups DFS tree children by their discovered parent.
Definition traversal.hpp:681
auto bfs_edges(const NodeID &start) const
Returns the tree edges discovered by breadth-first search.
Definition traversal.hpp:555
void depth_first_search(const NodeID &start, Visitor &visitor) const
Runs depth-first search with an object-style visitor.
Definition traversal.hpp:696
void breadth_first_search(const NodeID &start, Visitor &visitor) const
Runs breadth-first search with an object-style visitor.
Definition traversal.hpp:603
auto dfs_edges(const NodeID &start) const
Returns the tree edges discovered by depth-first search.
Definition traversal.hpp:632
auto bfs_successors(const NodeID &start) const
Groups BFS tree children by their discovered parent.
Definition traversal.hpp:588
auto dfs_tree(const NodeID &start) const
Materializes the depth-first-search tree rooted at start.
Definition traversal.hpp:662
Definition traversal.hpp:32
Minimal visitor interface for wrapper-level traversal callbacks.
Definition traversal.hpp:225
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:294
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:536
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:550
auto dfs_successors(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_successors(start).
Definition traversal.hpp:456
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:371
auto dfs_tree(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_tree(start).
Definition traversal.hpp:430
auto bfs_edges(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.bfs_edges(start).
Definition traversal.hpp:268
auto dfs_predecessors(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_predecessors(start).
Definition traversal.hpp:443
auto bfs_tree(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.bfs_tree(start).
Definition traversal.hpp:281
auto dfs_edges(const GraphWrapper &G, const typename GraphWrapper::NodeType &start)
Deprecated free-function alias for G.dfs_edges(start).
Definition traversal.hpp:417
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:385