Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
find_path_test.cc
Go to the documentation of this file.
1
6#include <gtest/gtest.h>
7#include <tpl_find_path.H>
8#include <tpl_graph.H>
9
10using namespace Aleph;
11
12// =============================================================================
13// Type Definitions
14// =============================================================================
15
17using Node = GT::Node;
18using Arc = GT::Arc;
19
20// =============================================================================
21// Test Fixture
22// =============================================================================
23
24class FindPathTest : public ::testing::Test
25{
26protected:
28
29 void SetUp() override
30 {
31 g = GT();
32 }
33
34 void TearDown() override {}
35
36 // Helper: create linear path graph: n0 -> n1 -> n2 -> ... -> n(n-1)
37 std::vector<Node*> create_linear_graph(size_t n)
38 {
39 std::vector<Node*> nodes;
40 for (size_t i = 0; i < n; ++i)
41 nodes.push_back(g.insert_node(i));
42
43 for (size_t i = 0; i < n - 1; ++i)
44 g.insert_arc(nodes[i], nodes[i + 1]);
45
46 return nodes;
47 }
48
49 // Helper: create complete graph
50 std::vector<Node*> create_complete_graph(size_t n)
51 {
52 std::vector<Node*> nodes;
53 for (size_t i = 0; i < n; ++i)
54 nodes.push_back(g.insert_node(i));
55
56 for (size_t i = 0; i < n; ++i)
57 for (size_t j = i + 1; j < n; ++j)
58 g.insert_arc(nodes[i], nodes[j]);
59
60 return nodes;
61 }
62};
63
64// =============================================================================
65// Depth-First Path Tests
66// =============================================================================
67
69{
70 auto nodes = create_linear_graph(5);
71
73 Path<GT> path(g);
74
75 bool found = finder(g, nodes[0], nodes[4], path);
76
78 EXPECT_FALSE(path.is_empty());
79 EXPECT_EQ(path.size(), 5u);
80}
81
83{
84 auto n = g.insert_node(0);
85
87 Path<GT> path(g);
88
89 bool found = finder(g, n, n, path);
90
92}
93
95{
96 auto n1 = g.insert_node(1);
97 auto n2 = g.insert_node(2);
98 auto n3 = g.insert_node(3);
99
100 g.insert_arc(n1, n2);
101 // n3 is disconnected
102
103 try {
105 Path<GT> path(g);
106 bool found = finder(g, n1, n3, path);
108 } catch (...) {
109 // Empty path may throw - this is expected
110 SUCCEED();
111 }
112}
113
115{
116 auto nodes = create_complete_graph(10);
117
119 Path<GT> path(g);
120
121 bool found = finder(g, nodes[0], nodes[9], path);
122
124 EXPECT_FALSE(path.is_empty());
125}
126
128{
129 auto nodes = create_linear_graph(10);
130
132
133 // Find node with value 7
134 auto path = finder(g, nodes[0], [](Node* p) { return p->get_info() == 7; });
135
136 EXPECT_FALSE(path.is_empty());
137}
138
140{
141 const auto nodes = create_linear_graph(5);
142
143 // Look for value 100 (doesn't exist) - returns empty path, no exception
144 try
145 {
147 const auto path = finder(g, nodes[0], [](Node* p) { return p->get_info() == 100; });
148 EXPECT_TRUE(path.is_empty());
149 } catch (...) {
150 // Empty path iteration throws exception - this is expected behavior
151 SUCCEED();
152 }
153}
154
155// =============================================================================
156// Breadth-First Path Tests
157// =============================================================================
158
160{
161 auto nodes = create_linear_graph(5);
162
164 Path<GT> path(g);
165
166 bool found = finder(g, nodes[0], nodes[4], path);
167
169 EXPECT_FALSE(path.is_empty());
170}
171
173{
174 auto n = g.insert_node(0);
175
177
178 auto path = finder(g, n, n);
179
180 // BFS path to self - may be empty or have single node depending on implementation
181 // Just verify it was created without error
182 SUCCEED();
183}
184
186{
187 auto n1 = g.insert_node(1);
188 auto n2 = g.insert_node(2);
189 auto n3 = g.insert_node(3);
190
191 g.insert_arc(n1, n2);
192 // n3 disconnected
193
195 Path<GT> path(g);
196
197 bool found = finder(g, n1, n3, path);
198
200}
201
203{
204 /*
205 * Create diamond graph:
206 * n1
207 * / \
208 * n2 n3
209 * \ /
210 * n4
211 */
212 auto n1 = g.insert_node(1);
213 auto n2 = g.insert_node(2);
214 auto n3 = g.insert_node(3);
215 auto n4 = g.insert_node(4);
216
217 g.insert_arc(n1, n2);
218 g.insert_arc(n1, n3);
219 g.insert_arc(n2, n4);
220 g.insert_arc(n3, n4);
221
223 auto path = finder(g, n1, n4);
224
225 EXPECT_FALSE(path.is_empty());
226 EXPECT_EQ(path.size(), 3u); // n1 -> n2/n3 -> n4 (shortest)
227}
228
230{
231 auto nodes = create_complete_graph(8);
232
234 auto path = finder(g, nodes[0], nodes[7]);
235
236 EXPECT_FALSE(path.is_empty());
237}
238
240{
241 auto nodes = create_linear_graph(10);
242
244
245 auto path = finder(g, nodes[0], [](Node* p) { return p->get_info() == 5; });
246
247 EXPECT_FALSE(path.is_empty());
248}
249
250// =============================================================================
251// Directed Graph Path Tests
252// =============================================================================
253
255{
257 DGT dg;
258
259 auto n1 = dg.insert_node(1);
260 auto n2 = dg.insert_node(2);
261 auto n3 = dg.insert_node(3);
262
263 dg.insert_arc(n1, n2);
264 dg.insert_arc(n2, n3);
265
267 auto path = finder.dfs(n1, n3);
268
269 EXPECT_FALSE(path.is_empty());
270 EXPECT_EQ(path.size(), 3u);
271}
272
274{
276 DGT dg;
277
278 auto n1 = dg.insert_node(1);
279 auto n2 = dg.insert_node(2);
280 auto n3 = dg.insert_node(3);
281
282 dg.insert_arc(n1, n2);
283 dg.insert_arc(n2, n3);
284
286 auto path = finder.bfs(n1, n3);
287
288 EXPECT_FALSE(path.is_empty());
289}
290
292{
294 DGT dg;
295
296 auto n1 = dg.insert_node(1);
297 auto n2 = dg.insert_node(2);
298 auto n3 = dg.insert_node(3);
299
300 dg.insert_arc(n1, n2);
301 dg.insert_arc(n3, n2); // n3 -> n2, can't reach n3 from n1
302
304 auto path = finder.dfs(n1, n3);
305
306 EXPECT_TRUE(path.is_empty());
307}
308
310{
312 DGT dg;
313
314 auto n1 = dg.insert_node(1);
315 auto n2 = dg.insert_node(2);
316 auto n3 = dg.insert_node(3);
317
318 dg.insert_arc(n1, n2);
319 dg.insert_arc(n2, n3);
320
322 auto path = finder.dfs(n1, [](DGT::Node* p) { return p->get_info() == 3; });
323
324 EXPECT_FALSE(path.is_empty());
325}
326
327// =============================================================================
328// Stress Tests
329// =============================================================================
330
332{
333 auto nodes = create_linear_graph(1000);
334
336 auto dfs_path = dfs_finder(g, nodes[0], nodes[999]);
337
339 EXPECT_EQ(dfs_path.size(), 1000u);
340}
341
343{
344 auto nodes = create_complete_graph(50);
345
347 auto path = bfs_finder(g, nodes[0], nodes[49]);
348
349 EXPECT_FALSE(path.is_empty());
350 EXPECT_LE(path.size(), 3u); // Should find direct path
351}
352
353// =============================================================================
354// Edge Cases
355// =============================================================================
356
358{
359 auto n = g.insert_node(1);
360
362 auto path = finder(g, n, n);
363
364 EXPECT_EQ(path.size(), 1u);
365}
366
368{
369 auto n1 = g.insert_node(1);
370 auto n2 = g.insert_node(2);
371 g.insert_arc(n1, n2);
372
374 auto path = finder(g, n1, n2);
375
376 EXPECT_FALSE(path.is_empty());
377 EXPECT_EQ(path.size(), 2u);
378}
379
381{
382 auto n1 = g.insert_node(1);
383 auto n2 = g.insert_node(2);
384
385 try {
387 auto path = finder(g, n1, n2);
388 // Empty path - expected behavior
389 SUCCEED();
390 } catch (...) {
391 // Exception on empty path is also valid
392 SUCCEED();
393 }
394}
395
397{
398 auto n1 = g.insert_node(1);
399 auto n2 = g.insert_node(2);
400 auto n3 = g.insert_node(3);
401
402 g.insert_arc(n1, n2);
403 g.insert_arc(n2, n3);
404 g.insert_arc(n3, n1); // Cycle
405
407 auto path = finder(g, n1, n3);
408
409 EXPECT_FALSE(path.is_empty());
410}
411
412// =============================================================================
413// Multiple Paths Tests
414// =============================================================================
415
417{
418 // Create graph with two paths from n1 to n4:
419 // n1 -> n2 -> n4
420 // n1 -> n3 -> n4
421 auto n1 = g.insert_node(1);
422 auto n2 = g.insert_node(2);
423 auto n3 = g.insert_node(3);
424 auto n4 = g.insert_node(4);
425
426 g.insert_arc(n1, n2);
427 g.insert_arc(n1, n3);
428 g.insert_arc(n2, n4);
429 g.insert_arc(n3, n4);
430
432 auto path = finder(g, n1, n4);
433
434 EXPECT_FALSE(path.is_empty());
435 EXPECT_EQ(path.size(), 3u);
436}
WeightedDigraph::Node Node
WeightedDigraph::Arc Arc
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
typename BaseGraph::Node Node
Definition graph-dry.H:3851
Búsqueda de caminos sobre grafos dirigidos definidos mediante una clase grafo (no digrafo).
Busca en amplitud un camino entre un par de nodos.
Busca en profundidad un camino entre un par de nodos.
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Graph_Arc< int > Arc
The node class type.
Definition tpl_graph.H:433
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Path on a graph.
Definition tpl_graph.H:2669
size_t size() const noexcept
Return the path length in nodes.
Definition tpl_graph.H:2807
bool is_empty() const noexcept
Return true if the path is empty.
Definition tpl_graph.H:2813
void SetUp() override
std::vector< Node * > create_linear_graph(size_t n)
std::vector< Node * > create_complete_graph(size_t n)
void TearDown() override
List_Graph< Graph_Node< int >, Graph_Arc< int > > GT
TEST_F(FindPathTest, DFS_SimplePath)
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Path finding algorithms in graphs.
Generic graph and digraph implementations.