Skip to content

Commit d82eed4

Browse files
committed
gl alg tmpl docs
1 parent 36bb238 commit d82eed4

5 files changed

Lines changed: 250 additions & 7 deletions

File tree

include/gl/algorithm/templates/bfs.hpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
33
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
44

5+
/// @file gl/algorithm/templates/bfs.hpp
6+
/// @brief Generic Breadth-First Search (BFS) template algorithm engine.
7+
58
#pragma once
69

710
#include "gl/algorithm/core.hpp"
@@ -12,7 +15,62 @@
1215

1316
namespace gl::algorithm {
1417

15-
/// @ingroup GL-Algorithm
18+
/// @ingroup GL GL-Algorithm
19+
/// @brief A highly customizable, generic Breadth-First Search (BFS) algorithm engine.
20+
///
21+
/// This template does not implement a specific algorithm (like finding a shortest path).
22+
/// Instead, it provides the strict structural execution of a queue-based Breadth-First Search.
23+
/// Concrete algorithms are constructed by injecting logic into the provided callback and
24+
/// predicate hooks.
25+
///
26+
/// ### Example Usage
27+
/// ```cpp
28+
/// std::vector<bool> visited(graph.n_vertices(), false); // (1)!
29+
///
30+
/// bool completed = gl::algorithm::bfs(
31+
/// graph,
32+
/// gl::algorithm::init_range<graph_type>(start_id), // (2)!
33+
/// gl::algorithm::default_visit_vertex_predicate(visited), // (3)!
34+
/// [&](auto v, auto p) { // (4)!
35+
/// std::cout << "Visited vertex " << v << '\n';
36+
/// return true; // Continue search
37+
/// },
38+
/// gl::algorithm::default_enqueue_vertex_predicate<graph_type, true>(visited) // (5)!
39+
/// );
40+
/// ```
41+
///
42+
/// 1\. Tracks discovered vertices.
43+
///
44+
/// 2\. Initializes the search queue with the starting vertex.
45+
///
46+
/// 3\. Predicate ensuring we don't process a vertex if it was already marked visited.
47+
///
48+
/// 4\. The main visit callback. Here we just print the ID. Returning `false` would abort the search.
49+
///
50+
/// 5\. Predicate ensuring we only enqueue adjacent vertices that haven't been visited yet, returning a @ref gl::algorithm::decision "decision".
51+
///
52+
/// ### Template Parameters
53+
/// | Parameter | Description |
54+
/// | :-------- | :--- |
55+
/// | G | The type of the graph being traversed. |
56+
/// | InitQueueRangeType | The type of the container providing the initial roots to enqueue. |
57+
/// | VisitVertexPredicate | Type of the callable deciding if a popped vertex should be processed. |
58+
/// | VisitCallback | Type of the callable executed when a vertex is officially visited. |
59+
/// | EnqueueVertexPred | Type of the callable deciding if an adjacent vertex should be pushed to the queue. |
60+
/// | PreVisitCallback | Type of the callable executed immediately before `VisitCallback`. |
61+
/// | PostVisitCallback | Type of the callable executed after all adjacent edges are evaluated. |
62+
///
63+
/// @param graph The graph to traverse.
64+
/// @param initial_queue_content A range of initial @ref gl::algorithm::search_node "search nodes" to seed the BFS queue.
65+
/// @param visit_vertex_pred Predicate evaluated immediately after popping a vertex. If it returns `false`, the vertex is skipped.
66+
/// @param visit Callback invoked when a vertex is officially visited. If it returns `false`, the entire BFS immediately aborts.
67+
/// @param enqueue_vertex_pred Predicate evaluated for each outgoing edge. Returns a @ref gl::algorithm::decision "decision":
68+
/// - `accept` to enqueue,
69+
/// - `reject` to skip,
70+
/// - `abort` to terminate the BFS entirely.
71+
/// @param pre_visit Hook executed immediately before the `visit` callback.
72+
/// @param post_visit Hook executed after all adjacent edges of the current vertex have been evaluated.
73+
/// @return `true` if the queue was exhausted naturally, `false` if the search was aborted early by a callback or predicate.
1674
template <
1775
traits::c_graph G,
1876
traits::c_forward_range_of<search_node<G>> InitQueueRangeType = std::vector<search_node<G>>,

include/gl/algorithm/templates/dfs.hpp

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
33
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
44

5+
/// @file gl/algorithm/templates/dfs.hpp
6+
/// @brief Generic Depth-First Search (DFS) template algorithm engines (iterative and recursive).
7+
58
#pragma once
69

710
#include "gl/algorithm/core.hpp"
@@ -12,6 +15,61 @@
1215

1316
namespace gl::algorithm {
1417

18+
/// @ingroup GL GL-Algorithm
19+
/// @brief A highly customizable, generic iterative Depth-First Search (DFS) algorithm engine.
20+
///
21+
/// This engine provides the strict structural execution of a stack-based Depth-First Search.
22+
/// Concrete algorithms (like cycle detection or topological sorting) are built by injecting
23+
/// specific logic into the provided callback hooks.
24+
///
25+
/// ### Example Usage
26+
/// ```cpp
27+
/// std::vector<bool> visited(graph.n_vertices(), false); // (1)!
28+
///
29+
/// bool completed = gl::algorithm::dfs(
30+
/// graph,
31+
/// gl::algorithm::init_range<graph_type>(start_id), // (2)!
32+
/// gl::algorithm::default_visit_vertex_predicate(visited), // (3)!
33+
/// [&](auto v, auto p) { // (4)!
34+
/// std::cout << "Visited vertex " << v << '\n';
35+
/// return true; // Continue search
36+
/// },
37+
/// gl::algorithm::default_enqueue_vertex_predicate<graph_type, true>(visited) // (5)!
38+
/// );
39+
/// ```
40+
///
41+
/// 1\. Tracks discovered vertices.
42+
///
43+
/// 2\. Initializes the search stack with the starting vertex.
44+
///
45+
/// 3\. Predicate ensuring we don't process a vertex if it was already marked visited.
46+
///
47+
/// 4\. The main visit callback. Returning `false` would abort the search.
48+
///
49+
/// 5\. Predicate ensuring we only push adjacent, unvisited vertices to the stack, returning a @ref gl::algorithm::decision "decision".
50+
///
51+
/// ### Template Parameters
52+
/// | Parameter | Description |
53+
/// | :-------- | :--- |
54+
/// | G | The type of the graph being traversed. |
55+
/// | InitStackRangeType | The type of the container providing the initial roots to push to the stack. |
56+
/// | VisitVertexPredicate | Type of the callable deciding if a popped vertex should be processed. |
57+
/// | VisitCallback | Type of the callable executed when a vertex is officially visited. |
58+
/// | EnqueueVertexPred | Type of the callable deciding if an adjacent vertex should be pushed to the stack. |
59+
/// | PreVisitCallback | Type of the callable executed immediately before `VisitCallback`. |
60+
/// | PostVisitCallback | Type of the callable executed after all adjacent edges are evaluated. |
61+
///
62+
/// @param graph The graph to traverse.
63+
/// @param initial_stack_content A range of initial @ref gl::algorithm::search_node "search nodes" to seed the DFS stack.
64+
/// @param visit_vertex_pred Predicate evaluated immediately after popping a vertex. If it returns `false`, the vertex is skipped.
65+
/// @param visit Callback invoked when a vertex is officially visited. If it returns `false`, the entire DFS immediately aborts.
66+
/// @param enqueue_vertex_pred Predicate evaluated for each outgoing edge. Returns a @ref gl::algorithm::decision "decision":
67+
/// - `accept` to enqueue,
68+
/// - `reject` to skip,
69+
/// - `abort` to terminate the DFS entirely.
70+
/// @param pre_visit Hook executed immediately before the `visit` callback.
71+
/// @param post_visit Hook executed after all adjacent edges of the current vertex have been evaluated.
72+
/// @return `true` if the stack was exhausted naturally, `false` if the search was aborted early.
1573
template <
1674
traits::c_graph G,
1775
traits::c_forward_range_of<search_node<G>> InitStackRangeType = std::vector<search_node<G>>,
@@ -57,7 +115,10 @@ bool dfs(
57115

58116
for (const auto& edge : graph.out_edges(node.vertex_id)) {
59117
const auto target_vertex_id = edge.other(node.vertex_id);
60-
if (enqueue_vertex_pred(target_vertex_id, edge))
118+
const auto enqueue = enqueue_vertex_pred(target_vertex_id, edge);
119+
if (enqueue == decision::abort)
120+
return false;
121+
if (enqueue)
61122
s.emplace(target_vertex_id, node.vertex_id);
62123
}
63124

@@ -68,6 +129,60 @@ bool dfs(
68129
return true;
69130
}
70131

132+
/// @ingroup GL GL-Algorithm
133+
/// @brief A highly customizable, generic recursive Depth-First Search (DFS) algorithm engine.
134+
///
135+
/// This engine mirrors the iterative `dfs` behavior but utilizes the C++ call stack.
136+
/// It does not accept an initial range, but instead is kicked off for a specific root vertex.
137+
/// It does not return a boolean abort signal; logic flow must be managed by the injected callbacks.
138+
///
139+
/// ### Example Usage
140+
/// ```cpp
141+
/// std::vector<bool> visited(graph.n_vertices(), false); // (1)!
142+
///
143+
/// gl::algorithm::r_dfs(
144+
/// graph,
145+
/// start_id, // (2)!
146+
/// gl::algorithm::no_root, // (3)!
147+
/// gl::algorithm::default_visit_vertex_predicate(visited), // (4)!
148+
/// [&](auto v, auto p) { // (5)!
149+
/// std::cout << "Recursively visiting vertex " << v << '\n';
150+
/// return true;
151+
/// },
152+
/// gl::algorithm::default_enqueue_vertex_predicate<graph_type, false>(visited) // (6)!
153+
/// );
154+
/// ```
155+
///
156+
/// 1\. Tracks discovered vertices.
157+
///
158+
/// 2\. The ID of the starting vertex for the recursion.
159+
///
160+
/// 3\. Indicates that the starting vertex has no predecessor.
161+
///
162+
/// 4\. Predicate evaluated upon entering the recursive call to prevent duplicate processing.
163+
///
164+
/// 5\. The main visit callback.
165+
///
166+
/// 6\. Predicate evaluating whether to recursively traverse into the target vertex.
167+
///
168+
/// ### Template Parameters
169+
/// | Parameter | Description |
170+
/// | :-------- | :--- |
171+
/// | G | The type of the graph being traversed. |
172+
/// | VisitVertexPredicate | Type of the callable deciding if the current vertex should be processed. |
173+
/// | VisitCallback | Type of the callable executed when the vertex is officially visited. |
174+
/// | EnqueueVertexPred | Type of the callable deciding if an adjacent vertex should be recursed into. |
175+
/// | PreVisitCallback | Type of the callable executed immediately before `VisitCallback`. |
176+
/// | PostVisitCallback | Type of the callable executed after all adjacent edges are evaluated. |
177+
///
178+
/// @param graph The graph to traverse.
179+
/// @param vertex_id The ID of the vertex currently being visited.
180+
/// @param pred_id The ID of the predecessor vertex.
181+
/// @param visit_vertex_pred Predicate evaluated immediately upon entry. If it returns `false`, recursion returns early.
182+
/// @param visit Callback invoked when a vertex is officially visited.
183+
/// @param enqueue_vertex_pred Predicate evaluated for each outgoing edge. If `true`, the target is recursed into.
184+
/// @param pre_visit Hook executed immediately before the `visit` callback.
185+
/// @param post_visit Hook executed after returning from all adjacent recursive calls.
71186
template <
72187
traits::c_graph G,
73188
traits::c_optional_predicate<typename G::id_type> VisitVertexPredicate,

include/gl/algorithm/templates/pfs.hpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
33
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
44

5+
/// @file gl/algorithm/pfs.hpp
6+
/// @brief Generic Priority-First Search (PFS) template algorithm engine.
7+
58
#pragma once
69

710
#include "gl/algorithm/core.hpp"
@@ -12,6 +15,73 @@
1215

1316
namespace gl::algorithm {
1417

18+
/// @ingroup GL GL-Algorithm
19+
/// @brief A highly customizable, generic Priority-First Search (PFS) algorithm engine.
20+
///
21+
/// This template provides the strict structural execution of a priority queue-based search.
22+
/// It acts as the underlying engine for algorithms like Dijkstra's Shortest Path Search.
23+
/// Concrete algorithms are constructed by injecting logic into the provided callbacks and
24+
/// defining the custom priority comparator.
25+
///
26+
/// ### Example Usage
27+
/// ```cpp
28+
/// auto cmp = [](const auto& lhs, const auto& rhs) { // (1)!
29+
/// return lhs.vertex_id > rhs.vertex_id; // Min-heap based on ID
30+
/// };
31+
///
32+
/// std::vector<bool> visited(graph.n_vertices(), false); // (2)!
33+
///
34+
/// bool completed = gl::algorithm::pfs(
35+
/// graph,
36+
/// cmp, // (3)!
37+
/// gl::algorithm::init_range<graph_type>(start_id), // (4)!
38+
/// gl::algorithm::default_visit_vertex_predicate(visited), // (5)!
39+
/// [&](auto v, auto p) { // (6)!
40+
/// std::cout << "Priority visited vertex " << v << '\n';
41+
/// return true; // Continue search
42+
/// },
43+
/// gl::algorithm::default_enqueue_vertex_predicate<graph_type, true>(visited) // (7)!
44+
/// );
45+
/// ```
46+
///
47+
/// 1\. A custom comparator for the internal priority queue.
48+
///
49+
/// 2\. Tracks discovered vertices.
50+
///
51+
/// 3\. Injects the comparator to order the search exploration.
52+
///
53+
/// 4\. Initializes the priority queue with the starting vertex.
54+
///
55+
/// 5\. Predicate evaluated after popping the highest priority vertex.
56+
///
57+
/// 6\. The main visit callback. Returning `false` aborts the search.
58+
///
59+
/// 7\. Predicate determining if an adjacent vertex should be pushed into the priority queue.
60+
///
61+
/// ### Template Parameters
62+
/// | Parameter | Description |
63+
/// | :-------- | :--- |
64+
/// | G | The type of the graph being traversed. |
65+
/// | PQCompare | The comparator type used to order elements within the internal `std::priority_queue`. |
66+
/// | InitQueueRangeType | The type of the container providing the initial roots to enqueue. |
67+
/// | VisitVertexPredicate | Type of the callable deciding if a popped vertex should be processed. |
68+
/// | VisitCallback | Type of the callable executed when a vertex is officially visited. |
69+
/// | EnqueueVertexPred | Type of the callable deciding if an adjacent vertex should be pushed to the queue. |
70+
/// | PreVisitCallback | Type of the callable executed immediately before `VisitCallback`. |
71+
/// | PostVisitCallback | Type of the callable executed after all adjacent edges are evaluated. |
72+
///
73+
/// @param graph The graph to traverse.
74+
/// @param pq_compare The comparator instance used to determine priority (highest priority is popped first).
75+
/// @param initial_queue_content A range of initial @ref gl::algorithm::search_node "search nodes" to seed the priority queue.
76+
/// @param visit_vertex_pred Predicate evaluated immediately after popping a vertex. If it returns `false`, the vertex is skipped (often used for late-rejection in Dijkstra).
77+
/// @param visit Callback invoked when a vertex is officially visited. If it returns `false`, the entire PFS immediately aborts.
78+
/// @param enqueue_vertex_pred Predicate evaluated for each outgoing edge. Returns a @ref gl::algorithm::decision "decision":
79+
/// - `accept` to enqueue,
80+
/// - `reject` to skip,
81+
/// - `abort` to terminate the PFS entirely.
82+
/// @param pre_visit Hook executed immediately before the `visit` callback.
83+
/// @param post_visit Hook executed after all adjacent edges of the current vertex have been evaluated.
84+
/// @return `true` if the queue was exhausted naturally, `false` if the search was aborted early by a callback or predicate.
1585
template <
1686
traits::c_graph G,
1787
traits::c_predicate<search_node<G>, search_node<G>> PQCompare,

include/gl/algorithm/traversal/depth_first_search.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ result_type<Result, predecessors_map<G>> depth_first_search(
3535
init_range<G>(root_vertex_id),
3636
default_visit_vertex_predicate(visited),
3737
default_visit_callback<G, Result>(visited, pred_map),
38-
default_enqueue_vertex_predicate<G>(visited),
38+
default_enqueue_vertex_predicate<G, true>(visited),
3939
pre_visit,
4040
post_visit
4141
);
@@ -47,7 +47,7 @@ result_type<Result, predecessors_map<G>> depth_first_search(
4747
init_range<G>(root_id),
4848
default_visit_vertex_predicate(visited),
4949
default_visit_callback<G, Result>(visited, pred_map),
50-
default_enqueue_vertex_predicate<G>(visited),
50+
default_enqueue_vertex_predicate<G, true>(visited),
5151
pre_visit,
5252
post_visit
5353
);

include/gl/algorithm/util.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,13 @@ template <traits::c_graph G, result_discriminator Result>
8888
/// @ingroup GL GL-Algorithm
8989
/// @brief Generates a default lambda predicate that checks if an adjacent vertex should be enqueued into the search frontier.
9090
/// @tparam G The type of the graph.
91-
/// @tparam AsResult If `true`, the generated predicate returns a @ref decision instead of a raw boolean.
91+
/// @tparam AsDecision If `true`, the generated predicate returns a @ref gl::algorithm::decision "decision" instead of a raw boolean.
9292
/// @param visited A reference to the boolean array tracking visited vertices.
9393
/// @return A callable predicate that returns `true` (or `decision::accept`) if the adjacent vertex has not been visited.
94-
template <traits::c_graph G, bool AsResult = false>
94+
template <traits::c_graph G, bool AsDecision = false>
9595
[[nodiscard]] gl_attr_force_inline auto default_enqueue_vertex_predicate(std::vector<bool>& visited
9696
) {
97-
using return_t = std::conditional_t<AsResult, decision, bool>;
97+
using return_t = std::conditional_t<AsDecision, decision, bool>;
9898
return [&](typename G::id_type vertex_id, const typename G::edge_type&) -> return_t {
9999
return not visited[to_idx(vertex_id)];
100100
};

0 commit comments

Comments
 (0)