Skip to content

Commit 507aba1

Browse files
committed
common alg header + is_reachable + tests alignment
1 parent 4627cf1 commit 507aba1

8 files changed

Lines changed: 219 additions & 124 deletions

File tree

include/gl/algorithm.hpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@
1010
#include "gl/algorithm/traits.hpp"
1111
#include "gl/algorithm/util.hpp"
1212

13-
#include "algorithm/templates/bfs.hpp"
14-
#include "algorithm/templates/dfs.hpp"
15-
#include "algorithm/templates/pfs.hpp"
13+
#include "gl/algorithm/templates/bfs.hpp"
14+
#include "gl/algorithm/templates/dfs.hpp"
15+
#include "gl/algorithm/templates/pfs.hpp"
1616

17-
#include "algorithm/traversal/breadth_first_search.hpp"
18-
#include "algorithm/traversal/depth_first_search.hpp"
17+
#include "gl/algorithm/traversal/breadth_first_search.hpp"
18+
#include "gl/algorithm/traversal/depth_first_search.hpp"
1919

20-
#include "algorithm/topology/coloring.hpp"
21-
#include "algorithm/topology/topological_sort.hpp"
20+
#include "gl/algorithm/topology/coloring.hpp"
21+
#include "gl/algorithm/topology/topological_sort.hpp"
2222

23-
#include "algorithm/pathfinding/dijkstra.hpp"
23+
#include "gl/algorithm/pathfinding/dijkstra.hpp"
2424

25-
#include "algorithm/spanning_tree/prim_mst.hpp"
25+
#include "gl/algorithm/spanning_tree/prim_mst.hpp"
2626

2727
// clang-format on

include/hgl/algorithm.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2024-2026 Jakub Musiał
2+
// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
3+
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
4+
5+
#pragma once
6+
7+
// clang-format off
8+
9+
#include "hgl/algorithm/core.hpp"
10+
#include "hgl/algorithm/util.hpp"
11+
12+
#include "hgl/algorithm/templates/bfs.hpp"
13+
#include "hgl/algorithm/templates/dfs.hpp"
14+
15+
#include "hgl/algorithm/traversal/breadth_first_search.hpp"
16+
#include "hgl/algorithm/traversal/depth_first_search.hpp"
17+
#include "hgl/algorithm/traversal/backward_search.hpp"
18+
#include "hgl/algorithm/traversal/forward_search.hpp"
19+
20+
// clang-format on

include/hgl/algorithm/core.hpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@
77
#include "gl/algorithm/core.hpp"
88
#include "gl/algorithm/traits.hpp"
99
#include "gl/algorithm/util.hpp"
10+
#include "gl/traits.hpp"
1011
#include "hgl/hypergraph.hpp"
1112
#include "hgl/traits.hpp"
1213
#include "hgl/types.hpp"
1314

14-
namespace hgl::algorithm {
15+
#include <ranges>
16+
17+
namespace hgl {
18+
19+
namespace algorithm {
1520

1621
// -- GL core ---
1722

@@ -55,6 +60,19 @@ struct search_node {
5560
template <hgl::traits::c_hypergraph H>
5661
using search_tree = std::vector<search_node<H>>;
5762

63+
} // namespace algorithm
64+
65+
namespace traits {
66+
67+
template <typename T>
68+
concept c_search_tree =
69+
c_random_access_range<T>
70+
and c_instantiation_of<std::ranges::range_value_t<T>, algorithm::search_node>;
71+
72+
} // namespace traits
73+
74+
namespace algorithm {
75+
5876
// --- generic algorithm traits ---
5977

6078
enum class traversal_direction : bool { forward, backward };
@@ -95,6 +113,5 @@ struct traversal_policy<H, traversal_direction::backward> {
95113
}
96114
};
97115

98-
} // namespace hgl::algorithm
99-
100-
// TODO! Validate `const Callback&` vs `Callback&&` in alg templates
116+
} // namespace algorithm
117+
} // namespace hgl

include/hgl/algorithm/util.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ template <result_discriminator ResultDiscriminator, hgl::traits::c_hypergraph Hy
2020
return return_t();
2121
}
2222

23-
// TODO: is_reachable
23+
[[nodiscard]] gl_attr_force_inline bool is_reachable(
24+
const traits::c_search_tree auto& tree, traits::c_id_type auto vertex_id
25+
) noexcept {
26+
return tree[gl::to_idx(vertex_id)].pred_id != invalid_id;
27+
}
2428

2529
template <hgl::traits::c_hypergraph HypergraphType>
2630
[[nodiscard]] gl_attr_force_inline std::vector<search_node<HypergraphType>> init_range(

tests/source/hgl/test_alg_backward_search.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ TEST_CASE_TEMPLATE_DEFINE(
2121
hypergraph_type hypergraph;
2222
std::vector<id_type> root_vertices;
2323

24-
std::vector<id_type> expected_previsit_order;
25-
std::vector<id_type> expected_postvisit_order;
24+
std::vector<id_type> expected_visit_order;
2625
std::vector<id_type> expected_pred_map;
2726
std::vector<id_type> expected_in_hyperedges;
27+
std::vector<id_type> unreachable_vertices;
2828

2929
/* Topology:
3030
V = {v0, v1, v2, v3, v4}
@@ -58,28 +58,28 @@ TEST_CASE_TEMPLATE_DEFINE(
5858

5959
SUBCASE("single root v0 (immediate halt)") {
6060
root_vertices = {0u};
61-
expected_previsit_order = {0u};
62-
expected_postvisit_order = {0u};
61+
expected_visit_order = {0u};
6362
expected_pred_map.resize(order, hgl::invalid_id);
6463
expected_pred_map[0uz] = 0u;
6564
expected_in_hyperedges.resize(order, hgl::invalid_id);
65+
unreachable_vertices = {1u, 2u, 3u, 4u};
6666
}
6767

6868
SUBCASE("roots v0 and v1 (complete traversal)") {
6969
root_vertices = {0u, 1u};
70-
expected_previsit_order = {0u, 1u, 2u, 4u, 3u};
71-
expected_postvisit_order = expected_previsit_order;
70+
expected_visit_order = {0u, 1u, 2u, 4u, 3u};
7271
// v0->v0(root), v1->v1(root), v1->v2 (e0), v2->v3 (e1), v2->v4 (e2)
7372
expected_pred_map = {0u, 1u, 1u, 2u, 1u};
7473
expected_in_hyperedges = {hgl::invalid_id, hgl::invalid_id, e0, e1, e2};
74+
unreachable_vertices = {};
7575
}
7676

7777
CAPTURE(hypergraph);
7878
CAPTURE(root_vertices);
79-
CAPTURE(expected_previsit_order);
80-
CAPTURE(expected_postvisit_order);
79+
CAPTURE(expected_visit_order);
8180
CAPTURE(expected_pred_map);
8281
CAPTURE(expected_in_hyperedges);
82+
CAPTURE(unreachable_vertices);
8383

8484
// --- noret search ---
8585

@@ -99,8 +99,8 @@ TEST_CASE_TEMPLATE_DEFINE(
9999
[&](const auto& node) { postvisit_order.push_back(node.vertex_id); }
100100
);
101101

102-
CHECK_EQ(previsit_order, expected_previsit_order);
103-
CHECK_EQ(postvisit_order, expected_postvisit_order);
102+
CHECK_EQ(previsit_order, expected_visit_order);
103+
CHECK_EQ(postvisit_order, expected_visit_order);
104104
CHECK_EQ(noret_pred_map, expected_pred_map);
105105
CHECK_EQ(noret_in_hyperedges, expected_in_hyperedges);
106106

@@ -117,6 +117,12 @@ TEST_CASE_TEMPLATE_DEFINE(
117117

118118
CHECK_EQ(ret_pred_map, expected_pred_map);
119119
CHECK_EQ(ret_in_hyperedges, expected_in_hyperedges);
120+
CHECK(std::ranges::all_of(expected_visit_order, [&search_tree](const auto v_id) {
121+
return hgl::algorithm::is_reachable(search_tree, v_id);
122+
}));
123+
CHECK(std::ranges::all_of(unreachable_vertices, [&search_tree](const auto v_id) {
124+
return not hgl::algorithm::is_reachable(search_tree, v_id);
125+
}));
120126
}
121127

122128
TEST_CASE_TEMPLATE_INSTANTIATE(
@@ -165,10 +171,10 @@ TEST_CASE_TEMPLATE_DEFINE(
165171
hypergraph_type hypergraph;
166172
std::vector<id_type> root_vertices;
167173

168-
std::vector<id_type> expected_previsit_order;
169-
std::vector<id_type> expected_postvisit_order;
174+
std::vector<id_type> expected_visit_order;
170175
std::vector<id_type> expected_pred_map;
171176
std::vector<id_type> expected_in_hyperedges;
177+
std::vector<id_type> unreachable_vertices;
172178

173179
/* Topology:
174180
V = {v0, v1, v2, v3, v4}
@@ -202,11 +208,11 @@ TEST_CASE_TEMPLATE_DEFINE(
202208

203209
SUBCASE("single root v0 (immediate halt)") {
204210
root_vertices = {0u};
205-
expected_previsit_order = {0u};
206-
expected_postvisit_order = {0u};
211+
expected_visit_order = {0u};
207212
expected_pred_map.resize(order, hgl::invalid_id);
208213
expected_pred_map[0uz] = 0u;
209214
expected_in_hyperedges.resize(order, hgl::invalid_id);
215+
unreachable_vertices = {1u, 2u, 3u, 4u};
210216
}
211217

212218
SUBCASE("roots v0 and v1 (complete traversal)") {
@@ -219,21 +225,21 @@ TEST_CASE_TEMPLATE_DEFINE(
219225
// Pop v0 -> unlocks e0 -> pushes v2.
220226
// Pop v2 -> unlocks e1 -> pushes v3, v4(visited).
221227
// Pop v3 -> no outgoing.
222-
expected_previsit_order = {1u, 4u, 0u, 2u, 3u};
223-
expected_postvisit_order = expected_previsit_order;
228+
expected_visit_order = {1u, 4u, 0u, 2u, 3u};
224229

225-
// Notice v2's pred is v0 now! (v0 was popped after v1, unlocking e0)
226230
// v0->v0(root), v1->v1(root), v2->v0 (via e0), v3->v2 (via e1), v4->v1 (via e2)
227231
expected_pred_map = {0u, 1u, 0u, 2u, 1u};
228232
expected_in_hyperedges = {hgl::invalid_id, hgl::invalid_id, e0, e1, e2};
233+
234+
unreachable_vertices = {};
229235
}
230236

231237
CAPTURE(hypergraph);
232238
CAPTURE(root_vertices);
233-
CAPTURE(expected_previsit_order);
234-
CAPTURE(expected_postvisit_order);
239+
CAPTURE(expected_visit_order);
235240
CAPTURE(expected_pred_map);
236241
CAPTURE(expected_in_hyperedges);
242+
CAPTURE(unreachable_vertices);
237243

238244
// --- noret search ---
239245

@@ -253,8 +259,8 @@ TEST_CASE_TEMPLATE_DEFINE(
253259
[&](const auto& node) { postvisit_order.push_back(node.vertex_id); }
254260
);
255261

256-
CHECK_EQ(previsit_order, expected_previsit_order);
257-
CHECK_EQ(postvisit_order, expected_postvisit_order);
262+
CHECK_EQ(previsit_order, expected_visit_order);
263+
CHECK_EQ(postvisit_order, expected_visit_order);
258264
CHECK_EQ(noret_pred_map, expected_pred_map);
259265
CHECK_EQ(noret_in_hyperedges, expected_in_hyperedges);
260266

@@ -271,6 +277,12 @@ TEST_CASE_TEMPLATE_DEFINE(
271277

272278
CHECK_EQ(ret_pred_map, expected_pred_map);
273279
CHECK_EQ(ret_in_hyperedges, expected_in_hyperedges);
280+
CHECK(std::ranges::all_of(expected_visit_order, [&search_tree](const auto v_id) {
281+
return hgl::algorithm::is_reachable(search_tree, v_id);
282+
}));
283+
CHECK(std::ranges::all_of(unreachable_vertices, [&search_tree](const auto v_id) {
284+
return not hgl::algorithm::is_reachable(search_tree, v_id);
285+
}));
274286
}
275287

276288
TEST_CASE_TEMPLATE_INSTANTIATE(

0 commit comments

Comments
 (0)