Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_spanning_tree_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
50#include <gtest/gtest.h>
51#include <tpl_spanning_tree.H>
52#include <tpl_graph.H>
53#include <tpl_sgraph.H>
54#include <tpl_agraph.H>
55
56using namespace Aleph;
57
58//==============================================================================
59// Graph Type Definitions - All 6 combinations
60//==============================================================================
61
62// List-based graphs (tpl_graph.H)
65
66// Sparse graphs (tpl_sgraph.H)
69
70// Array-based graphs (tpl_agraph.H)
73
74//==============================================================================
75// Test Fixtures
76//==============================================================================
77
78class DFSSpanningTreeTest : public ::testing::Test
79{
80protected:
84};
85
86class BFSSpanningTreeTest : public ::testing::Test
87{
88protected:
92};
93
94//==============================================================================
95// DFS Spanning Tree Basic Tests
96//==============================================================================
97
99{
100 [[maybe_unused]] auto n1 = g.insert_node(1);
101
103 auto root = dfs(g, tree);
104
105 ASSERT_NE(root, nullptr);
106 EXPECT_EQ(tree.get_num_nodes(), 1);
107 EXPECT_EQ(tree.get_num_arcs(), 0);
108}
109
111{
112 [[maybe_unused]] auto n1 = g.insert_node(1);
113 auto n2 = g.insert_node(2);
114 g.insert_arc(n1, n2);
115
117 auto root = dfs(g, tree);
118
119 ASSERT_NE(root, nullptr);
120 EXPECT_EQ(tree.get_num_nodes(), 2);
121 EXPECT_EQ(tree.get_num_arcs(), 1);
122}
123
125{
126 [[maybe_unused]] auto n1 = g.insert_node(1);
127 auto n2 = g.insert_node(2);
128 auto n3 = g.insert_node(3);
129 g.insert_arc(n1, n2);
130 g.insert_arc(n2, n3);
131 g.insert_arc(n3, n1);
132
134 auto root = dfs(g, tree);
135
136 ASSERT_NE(root, nullptr);
137 EXPECT_EQ(tree.get_num_nodes(), 3);
138 EXPECT_EQ(tree.get_num_arcs(), 2); // V-1 arcs
139}
140
142{
143 [[maybe_unused]] auto n1 = g.insert_node(1);
144 auto n2 = g.insert_node(2);
145 auto n3 = g.insert_node(3);
146 auto n4 = g.insert_node(4);
147 auto n5 = g.insert_node(5);
148
149 g.insert_arc(n1, n2);
150 g.insert_arc(n2, n3);
151 g.insert_arc(n3, n4);
152 g.insert_arc(n4, n5);
153
155 auto root = dfs(g, tree);
156
157 ASSERT_NE(root, nullptr);
158 EXPECT_EQ(tree.get_num_nodes(), 5);
159 EXPECT_EQ(tree.get_num_arcs(), 4);
160}
161
163{
164 const int N = 5;
166
167 for (int i = 0; i < N; ++i)
168 nodes.append(g.insert_node(i));
169
170 // Complete graph: connect all pairs
171 for (int i = 0; i < N; ++i)
172 for (int j = i + 1; j < N; ++j)
173 g.insert_arc(nodes(i), nodes(j));
174
176 auto root = dfs(g, tree);
177
178 ASSERT_NE(root, nullptr);
179 EXPECT_EQ(tree.get_num_nodes(), N);
180 EXPECT_EQ(tree.get_num_arcs(), N - 1); // Spanning tree has V-1 edges
181}
182
184{
185 [[maybe_unused]] auto n1 = g.insert_node(1);
186 auto n2 = g.insert_node(2);
187 auto n3 = g.insert_node(3);
188 g.insert_arc(n1, n2);
189 g.insert_arc(n2, n3);
190
192 auto tree_node = dfs(g, n2, tree); // Start from n2
193
194 ASSERT_NE(tree_node, nullptr);
195 EXPECT_EQ(tree.get_num_nodes(), 3);
196 EXPECT_EQ(tree.get_num_arcs(), 2);
197}
198
200{
202
203 EXPECT_THROW(dfs(g, tree), std::domain_error);
204}
205
207{
208 [[maybe_unused]] auto n1 = g.insert_node(1);
209
211
212 EXPECT_THROW(dfs(g, nullptr, tree), std::invalid_argument);
213}
214
216{
217 [[maybe_unused]] auto n1 = g.insert_node(10);
218 auto n2 = g.insert_node(20);
219 auto n3 = g.insert_node(30);
220 g.insert_arc(n1, n2);
221 g.insert_arc(n2, n3);
222
224 dfs(g, tree);
225
226 // Verify node mappings are established
227 auto t1 = mapped_node<Graph>(n1);
228 auto t2 = mapped_node<Graph>(n2);
229 auto t3 = mapped_node<Graph>(n3);
230
231 EXPECT_NE(t1, nullptr);
232 EXPECT_NE(t2, nullptr);
233 EXPECT_NE(t3, nullptr);
234
235 // Verify values are preserved
236 EXPECT_EQ(t1->get_info(), 10);
237 EXPECT_EQ(t2->get_info(), 20);
238 EXPECT_EQ(t3->get_info(), 30);
239}
240
241//==============================================================================
242// BFS Spanning Tree Basic Tests
243//==============================================================================
244
246{
247 [[maybe_unused]] auto n1 = g.insert_node(1);
248
250 auto root = bfs(g, tree);
251
252 ASSERT_NE(root, nullptr);
253 EXPECT_EQ(tree.get_num_nodes(), 1);
254 EXPECT_EQ(tree.get_num_arcs(), 0);
255}
256
258{
259 [[maybe_unused]] auto n1 = g.insert_node(1);
260 auto n2 = g.insert_node(2);
261 g.insert_arc(n1, n2);
262
264 auto root = bfs(g, tree);
265
266 ASSERT_NE(root, nullptr);
267 EXPECT_EQ(tree.get_num_nodes(), 2);
268 EXPECT_EQ(tree.get_num_arcs(), 1);
269}
270
272{
273 [[maybe_unused]] auto n1 = g.insert_node(1);
274 auto n2 = g.insert_node(2);
275 auto n3 = g.insert_node(3);
276 g.insert_arc(n1, n2);
277 g.insert_arc(n2, n3);
278 g.insert_arc(n3, n1);
279
281 auto root = bfs(g, tree);
282
283 ASSERT_NE(root, nullptr);
284 EXPECT_EQ(tree.get_num_nodes(), 3);
285 EXPECT_EQ(tree.get_num_arcs(), 2);
286}
287
289{
290 const int N = 5;
292
293 for (int i = 0; i < N; ++i)
294 nodes.append(g.insert_node(i));
295
296 for (int i = 0; i < N; ++i)
297 for (int j = i + 1; j < N; ++j)
298 g.insert_arc(nodes(i), nodes(j));
299
301 auto root = bfs(g, tree);
302
303 ASSERT_NE(root, nullptr);
304 EXPECT_EQ(tree.get_num_nodes(), N);
305 EXPECT_EQ(tree.get_num_arcs(), N - 1);
306}
307
309{
310 [[maybe_unused]] auto n1 = g.insert_node(1);
311 auto n2 = g.insert_node(2);
312 auto n3 = g.insert_node(3);
313 g.insert_arc(n1, n2);
314 g.insert_arc(n2, n3);
315
317 bfs(g, n2, tree); // Start from n2
318
319 EXPECT_EQ(tree.get_num_nodes(), 3);
320 EXPECT_EQ(tree.get_num_arcs(), 2);
321}
322
324{
326
327 EXPECT_THROW(bfs(g, tree), std::domain_error);
328}
329
331{
332 [[maybe_unused]] auto n1 = g.insert_node(1);
333
335
336 EXPECT_THROW(bfs(g, nullptr, tree), std::invalid_argument);
337}
338
340{
341 [[maybe_unused]] auto n1 = g.insert_node(10);
342 auto n2 = g.insert_node(20);
343 auto n3 = g.insert_node(30);
344 g.insert_arc(n1, n2);
345 g.insert_arc(n2, n3);
346
348 bfs(g, tree);
349
350 auto t1 = mapped_node<Graph>(n1);
351 auto t2 = mapped_node<Graph>(n2);
352 auto t3 = mapped_node<Graph>(n3);
353
354 EXPECT_NE(t1, nullptr);
355 EXPECT_NE(t2, nullptr);
356 EXPECT_NE(t3, nullptr);
357
358 EXPECT_EQ(t1->get_info(), 10);
359 EXPECT_EQ(t2->get_info(), 20);
360 EXPECT_EQ(t3->get_info(), 30);
361}
362
363//==============================================================================
364// Stress Tests
365//==============================================================================
366
368{
369 const int N = 100;
371
372 for (int i = 0; i < N; ++i)
373 nodes.append(g.insert_node(i));
374
375 // Create a connected graph
376 for (int i = 0; i < N - 1; ++i)
377 g.insert_arc(nodes(i), nodes(i + 1));
378
379 // Add some cross edges
380 for (int i = 0; i < N - 10; i += 10)
381 g.insert_arc(nodes(i), nodes(i + 10));
382
384 auto root = dfs(g, tree);
385
386 ASSERT_NE(root, nullptr);
387 EXPECT_EQ(tree.get_num_nodes(), N);
388 EXPECT_EQ(tree.get_num_arcs(), N - 1);
389}
390
392{
393 const int N = 100;
395
396 for (int i = 0; i < N; ++i)
397 nodes.append(g.insert_node(i));
398
399 for (int i = 0; i < N - 1; ++i)
400 g.insert_arc(nodes(i), nodes(i + 1));
401
402 for (int i = 0; i < N - 10; i += 10)
403 g.insert_arc(nodes(i), nodes(i + 10));
404
406 auto root = bfs(g, tree);
407
408 ASSERT_NE(root, nullptr);
409 EXPECT_EQ(tree.get_num_nodes(), N);
410 EXPECT_EQ(tree.get_num_arcs(), N - 1);
411}
412
413//==============================================================================
414// Typed Tests for All Graph Types
415//==============================================================================
416
417template <typename GraphType>
418class SpanningTreeAllGraphs : public ::testing::Test
419{
420protected:
423};
424
425using GraphTypes = ::testing::Types<
426 ListGraph,
432>;
433
435
436// Undirected graphs only - for tests that assume bidirectional traversal
437template <typename GraphType>
438class SpanningTreeUndirectedGraphs : public ::testing::Test
439{
440protected:
443};
444
445using UndirectedGraphTypes = ::testing::Types<
446 ListGraph,
449>;
450
452
454{
455 using Graph = TypeParam;
456 Graph & g = this->g;
457 Graph & tree = this->tree;
458
459 [[maybe_unused]] auto n1 = g.insert_node(1);
460
462 auto root = dfs(g, tree);
463
464 ASSERT_NE(root, nullptr);
465 EXPECT_EQ(tree.get_num_nodes(), 1);
466 EXPECT_EQ(tree.get_num_arcs(), 0);
467}
468
470{
471 using Graph = TypeParam;
472 Graph & g = this->g;
473 Graph & tree = this->tree;
474
475 [[maybe_unused]] auto n1 = g.insert_node(1);
476 auto n2 = g.insert_node(2);
477 auto n3 = g.insert_node(3);
478 g.insert_arc(n1, n2);
479 g.insert_arc(n2, n3);
480 g.insert_arc(n3, n1);
481
483 auto root = dfs(g, tree);
484
485 ASSERT_NE(root, nullptr);
486 EXPECT_EQ(tree.get_num_nodes(), 3);
487 EXPECT_EQ(tree.get_num_arcs(), 2);
488}
489
491{
492 using Graph = TypeParam;
493 Graph & g = this->g;
494 Graph & tree = this->tree;
495
497
498 EXPECT_THROW(dfs(g, tree), std::domain_error);
499}
500
502{
503 using Graph = TypeParam;
504 Graph & g = this->g;
505 Graph & tree = this->tree;
506
507 [[maybe_unused]] auto n1 = g.insert_node(1);
508
510
511 EXPECT_THROW(dfs(g, nullptr, tree), std::invalid_argument);
512}
513
515{
516 using Graph = TypeParam;
517 Graph & g = this->g;
518 Graph & tree = this->tree;
519
520 [[maybe_unused]] auto n1 = g.insert_node(1);
521
523 auto root = bfs(g, tree);
524
525 ASSERT_NE(root, nullptr);
526 EXPECT_EQ(tree.get_num_nodes(), 1);
527 EXPECT_EQ(tree.get_num_arcs(), 0);
528}
529
531{
532 using Graph = TypeParam;
533 Graph & g = this->g;
534 Graph & tree = this->tree;
535
536 [[maybe_unused]] auto n1 = g.insert_node(1);
537 auto n2 = g.insert_node(2);
538 auto n3 = g.insert_node(3);
539 g.insert_arc(n1, n2);
540 g.insert_arc(n2, n3);
541 g.insert_arc(n3, n1);
542
544 auto root = bfs(g, tree);
545
546 ASSERT_NE(root, nullptr);
547 EXPECT_EQ(tree.get_num_nodes(), 3);
548 EXPECT_EQ(tree.get_num_arcs(), 2);
549}
550
552{
553 using Graph = TypeParam;
554 Graph & g = this->g;
555 Graph & tree = this->tree;
556
558
559 EXPECT_THROW(bfs(g, tree), std::domain_error);
560}
561
563{
564 using Graph = TypeParam;
565 Graph & g = this->g;
566 Graph & tree = this->tree;
567
568 [[maybe_unused]] auto n1 = g.insert_node(1);
569
571
572 EXPECT_THROW(bfs(g, nullptr, tree), std::invalid_argument);
573}
574
576{
577 using Graph = TypeParam;
578 Graph & g = this->g;
579 Graph & tree = this->tree;
580
581 [[maybe_unused]] auto n1 = g.insert_node(1);
582 auto n2 = g.insert_node(2);
583 auto n3 = g.insert_node(3);
584 auto n4 = g.insert_node(4);
585 auto n5 = g.insert_node(5);
586
587 g.insert_arc(n1, n2);
588 g.insert_arc(n2, n3);
589 g.insert_arc(n3, n4);
590 g.insert_arc(n4, n5);
591
593 auto root = dfs(g, tree);
594
595 ASSERT_NE(root, nullptr);
596 EXPECT_EQ(tree.get_num_nodes(), 5);
597 EXPECT_EQ(tree.get_num_arcs(), 4);
598}
599
601{
602 using Graph = TypeParam;
603 Graph & g = this->g;
604 Graph & tree = this->tree;
605
606 [[maybe_unused]] auto n1 = g.insert_node(1);
607 auto n2 = g.insert_node(2);
608 auto n3 = g.insert_node(3);
609 auto n4 = g.insert_node(4);
610 auto n5 = g.insert_node(5);
611
612 g.insert_arc(n1, n2);
613 g.insert_arc(n2, n3);
614 g.insert_arc(n3, n4);
615 g.insert_arc(n4, n5);
616
618 auto root = bfs(g, tree);
619
620 ASSERT_NE(root, nullptr);
621 EXPECT_EQ(tree.get_num_nodes(), 5);
622 EXPECT_EQ(tree.get_num_arcs(), 4);
623}
624
625// Main
626int main(int argc, char **argv)
627{
628 ::testing::InitGoogleTest(&argc, argv);
629 return RUN_ALL_TESTS();
630}
int main()
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
T & append()
Allocate a new entry to the end of array.
Compute a breadth-first spanning tree of a graph.
Compute a depth-first spanning tree of a graph.
Arc for graphs implemented with simple adjacency lists.
Definition tpl_sgraph.H:197
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Graph class implemented with singly-linked adjacency lists.
Definition tpl_sgraph.H:274
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
constexpr size_t get_num_arcs() const noexcept
Definition graph-dry.H:778
#define N
Definition fib.C:294
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4060
::testing::Types< ListGraph, SparseGraph, ArrayGraph > UndirectedGraphTypes
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
Array-based graph implementation.
::testing::Types< ListGraph, ListDigraph, SparseGraph, SparseDigraph, ArrayGraph, ArrayDigraph > GraphTypes
Generic graph and digraph implementations.
Simple graph implementation with adjacency lists.
Spanning tree generation algorithms.
List_Digraph< Graph_Node< int >, Graph_Arc< int > > ListDigraph
TEST_F(DFSSpanningTreeTest, SingleNode)
TYPED_TEST(SpanningTreeAllGraphs, DFSSingleNode)
List_Graph< Graph_Node< int >, Graph_Arc< int > > ListGraph
Array_Graph< Graph_Anode< int >, Graph_Aarc< int > > ArrayGraph
TYPED_TEST_SUITE(SpanningTreeAllGraphs, GraphTypes)
List_SDigraph< Graph_Snode< int >, Graph_Sarc< int > > SparseDigraph
List_SGraph< Graph_Snode< int >, Graph_Sarc< int > > SparseGraph