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
77 EXPECT_TRUE(found);
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
91 EXPECT_TRUE(found);
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);
107 EXPECT_FALSE(found);
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
123 EXPECT_TRUE(found);
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
168 EXPECT_TRUE(found);
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
199 EXPECT_FALSE(found);
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
338 EXPECT_FALSE(dfs_path.is_empty());
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:3960
typename BaseGraph::Node Node
Definition graph-dry.H:3963
Path search on directed graphs defined through a graph class (not a digraph).
Performs a breadth-first search for a path between a pair of nodes.
Performs a depth-first search for a path between a pair of nodes.
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:525
Graph_Arc< int > Arc
The node class type.
Definition tpl_graph.H:434
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:605
Path on a graph.
Definition tpl_graph.H:2772
size_t size() const noexcept
Return the path length in nodes.
Definition tpl_graph.H:2910
bool is_empty() const noexcept
Return true if the path is empty.
Definition tpl_graph.H:2916
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
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:223
Path finding algorithms in graphs.
Generic graph and digraph implementations.