Skip to content

Commit 7a5d129

Browse files
committed
dfs docs
1 parent 7f355d9 commit 7a5d129

1 file changed

Lines changed: 74 additions & 3 deletions

File tree

  • include/hgl/algorithm/templates

include/hgl/algorithm/templates/dfs.hpp

Lines changed: 74 additions & 3 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 hgl/algorithm/templates/dfs.hpp
6+
/// @brief Generic Depth-First Search (DFS) template algorithm engine for hypergraphs.
7+
58
#pragma once
69

710
#include "hgl/algorithm/core.hpp"
@@ -10,14 +13,82 @@
1013

1114
namespace hgl::algorithm {
1215

16+
/// @ingroup HGL-Algorithm
17+
/// @brief A highly customizable, generic Depth-First Search (DFS) algorithm engine for hypergraphs.
18+
///
19+
/// This template provides the strict structural execution of a stack-based Depth-First Search
20+
/// over a hypergraph's topology. Because a hypergraph traversal inherently requires a two-step
21+
/// expansion (from a vertex to its incident hyperedges, and then to the adjacent vertices), this
22+
/// engine exposes specific hooks for both steps. Concrete algorithms are constructed by injecting
23+
/// logic into the provided callback and predicate hooks.
24+
///
25+
/// ### Example Usage
26+
/// ```cpp
27+
/// std::vector<bool> visited(hypergraph.n_vertices(), false); // (1)!
28+
///
29+
/// bool completed = hgl::algorithm::dfs(
30+
/// hypergraph,
31+
/// hgl::algorithm::init_node_range<H>(start_id), // (2)!
32+
/// [&](const auto& node) { return not visited[node.vertex_id]; }, // (3)!
33+
/// [&](const auto& node) { // (4)!
34+
/// visited[node.vertex_id] = true;
35+
/// std::cout << "Visited vertex " << node.vertex_id << '\n';
36+
/// return true; // Continue search
37+
/// },
38+
/// hgl::empty_callback{}, // (5)!
39+
/// [&](const auto& tgt_node) { return not visited[tgt_node.vertex_id]; } // (6)!
40+
/// );
41+
/// ```
42+
///
43+
/// 1\. Provide an external state array to track the visited vertices.
44+
///
45+
/// 2\. Initialize the search stack with a root @ref hgl::algorithm::search_node "search node" representing the starting point.
46+
///
47+
/// 3\. The *visit predicate* ensures vertices are not processed multiple times.
48+
///
49+
/// 4\. The concrete vertex visiting logic - marks the vertex as visited and logs it to the console.
50+
///
51+
/// 5\. Traverse all hyperedges unconditionally.
52+
///
53+
/// 6\. The *enqueue predicate* filters out already visited adjacent vertices before they are pushed to the stack.
54+
///
55+
/// ### Template Parameters
56+
/// | Parameter | Description | Constraint |
57+
/// | :-------- | :--- | :--- |
58+
/// | Dir | The @ref hgl::algorithm::traversal_direction "traversal direction" (i.e., `forward` or `backward`). Relevant only for BF-directed hypergraphs. | Defaults to `forward`. |
59+
/// | H | The type of the hypergraph being searched. | Must satisfy the [**c_hypergraph**](hgl_concepts.md#hgl-traits-c-hypergraph) concept. |
60+
/// | InitQueueRangeType | A forward range of `search_node<H>` used to prime the DFS stack. | Must be a *forward range* of @ref hgl::algorithm::search_node "search nodes". |
61+
/// | VisitPredicate | Type of the callable deciding if a popped node should be processed. | Must be one of:<br/>- A `(const search_node<H>&) -> bool` callable<br/>- An @ref hgl::algorithm::empty_callback "empty_callback" |
62+
/// | VisitCallback | Type of the callable executed when a vertex is officially visited. | Must be one of:<br/>- A `(const search_node<H>&) -> bool` callable<br/>- An @ref hgl::algorithm::empty_callback "empty_callback" |
63+
/// | TraverseHePredicate | Type of the callable deciding if an incident hyperedge should be traversed. | Must be one of:<br/>- An `(id_type, id_type) -> decision` callable<br/>- An @ref hgl::algorithm::empty_callback "empty_callback" |
64+
/// | EnqueuePredicate | Type of the callable deciding if a target vertex should be pushed to the stack via a specific hyperedge. | Must be one of:<br/>- A `(const search_node<H>&) -> decision` callable<br/>- An @ref hgl::algorithm::empty_callback "empty_callback" |
65+
/// | PreVisitCallback | Type of the callable executed immediately before `VisitCallback`. | Must be one of:<br/>- A `(const search_node<H>&) -> void` callable<br/>- An @ref hgl::algorithm::empty_callback "empty_callback" |
66+
/// | PostVisitCallback | Type of the callable executed after all adjacent elements are evaluated. | Must be one of:<br/>- A `(const search_node<H>&) -> void` callable<br/>- An @ref hgl::algorithm::empty_callback "empty_callback" |
67+
///
68+
/// @param hypergraph The hypergraph to traverse.
69+
/// @param initial_queue_content The initial set of search nodes to begin the traversal from.
70+
/// @param visit_pred Predicate to filter nodes immediately after popping them from the stack.
71+
/// @param visit Primary callback for node processing.
72+
/// @param traverse_he_pred Predicate to determine if an incident hyperedge should be traversed. Returns a @ref hgl::algorithm::decision "decision":
73+
/// - `accept` to traverse the hyperedge,
74+
/// - `reject` to skip the hyperedge,
75+
/// - `abort` to terminate the DFS entirely.
76+
/// @param enqueue_pred Predicate to determine if an adjacent vertex should be pushed to the stack via a hyperedge. Returns a @ref hgl::algorithm::decision "decision":
77+
/// - `accept` to push the vertex's search node,
78+
/// - `reject` to skip the node,
79+
/// - `abort` to terminate the DFS entirely.
80+
/// @param pre_visit Callback executed prior to the primary visit logic.
81+
/// @param post_visit Callback executed after all adjacent elements of the current node have been processed.
82+
/// @return `true` if the search completed normally, `false` if it was explicitly aborted via a callback.
83+
/// @hideparams
1384
template <
1485
traversal_direction Dir = traversal_direction::forward,
1586
traits::c_hypergraph H,
1687
traits::c_forward_range_of<search_node<H>> InitQueueRangeType = std::vector<search_node<H>>,
1788
traits::c_optional_predicate<const search_node<H>&> VisitPredicate = empty_callback,
1889
traits::c_optional_predicate<const search_node<H>&> VisitCallback = empty_callback,
1990
traits::c_optional_decision_predicate<typename H::id_type, typename H::id_type>
20-
TraverseHyperedgePredicate = empty_callback,
91+
TraverseHePredicate = empty_callback,
2192
traits::c_decision_predicate<const search_node<H>&> EnqueuePredicate = empty_callback,
2293
traits::c_optional_callback<void, const search_node<H>&> PreVisitCallback = empty_callback,
2394
traits::c_optional_callback<void, const search_node<H>&> PostVisitCallback = empty_callback>
@@ -26,7 +97,7 @@ bool dfs(
2697
const InitQueueRangeType& initial_queue_content,
2798
const VisitPredicate& visit_pred = {},
2899
const VisitCallback& visit = {},
29-
const TraverseHyperedgePredicate& traverse_he_pred = {},
100+
const TraverseHePredicate& traverse_he_pred = {},
30101
const EnqueuePredicate& enqueue_pred = {},
31102
const PreVisitCallback& pre_visit = {},
32103
const PostVisitCallback& post_visit = {}
@@ -56,7 +127,7 @@ bool dfs(
56127
return false;
57128

58129
for (const auto he_id : policy::target_hyperedges(hypergraph, curr_node.vertex_id)) {
59-
if constexpr (not traits::c_empty_callback<TraverseHyperedgePredicate>) {
130+
if constexpr (not traits::c_empty_callback<TraverseHePredicate>) {
60131
const auto traverse = traverse_he_pred(he_id, curr_node.vertex_id);
61132
if (traverse == decision::abort)
62133
return false;

0 commit comments

Comments
 (0)