Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_components_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_components.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 BuildSubgraphTest : public ::testing::Test
79{
80protected:
84};
85
86class InconnectedComponentsTest : public ::testing::Test
87{
88protected:
91};
92
93//==============================================================================
94// Build_Subgraph Basic Tests
95//==============================================================================
96
98{
99 [[maybe_unused]] auto n1 = g.insert_node(1);
100 g.reset_nodes();
101 g.reset_arcs();
102
104 builder(g, sg, n1);
105
106 EXPECT_EQ(sg.get_num_nodes(), 1);
107 EXPECT_EQ(sg.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 g.reset_nodes();
116 g.reset_arcs();
117
119 builder(g, sg, n1);
120
121 EXPECT_EQ(sg.get_num_nodes(), 2);
122 EXPECT_EQ(sg.get_num_arcs(), 1);
123}
124
126{
127 [[maybe_unused]] auto n1 = g.insert_node(1);
128 auto n2 = g.insert_node(2);
129 auto n3 = g.insert_node(3);
130 g.insert_arc(n1, n2);
131 g.insert_arc(n2, n3);
132 g.insert_arc(n3, n1);
133 g.reset_nodes();
134 g.reset_arcs();
135
137 builder(g, sg, n1);
138
139 EXPECT_EQ(sg.get_num_nodes(), 3);
140 EXPECT_EQ(sg.get_num_arcs(), 3);
141}
142
144{
145 // Create two disconnected components
146 [[maybe_unused]] auto n1 = g.insert_node(1);
147 auto n2 = g.insert_node(2);
148 g.insert_arc(n1, n2);
149
150 auto n3 = g.insert_node(3);
151 auto n4 = g.insert_node(4);
152 g.insert_arc(n3, n4);
153
154 g.reset_nodes();
155 g.reset_arcs();
156
158 builder(g, sg, n1);
159
160 // Should only build the component containing n1
161 EXPECT_EQ(sg.get_num_nodes(), 2);
162 EXPECT_EQ(sg.get_num_arcs(), 1);
163}
164
166{
167 [[maybe_unused]] auto n1 = g.insert_node(10);
168 auto n2 = g.insert_node(20);
169 g.insert_arc(n1, n2);
170 g.reset_nodes();
171 g.reset_arcs();
172
174 builder(g, sg, n1);
175
176 // Verify mappings
177 auto sg_n1 = mapped_node<Graph>(n1);
178 auto sg_n2 = mapped_node<Graph>(n2);
179
180 EXPECT_NE(sg_n1, nullptr);
181 EXPECT_NE(sg_n2, nullptr);
182 EXPECT_EQ(sg_n1->get_info(), 10);
183 EXPECT_EQ(sg_n2->get_info(), 20);
184}
185
187{
188 [[maybe_unused]] auto n1 = g.insert_node(1);
189 auto n2 = g.insert_node(2);
190 auto n3 = g.insert_node(3);
191 g.insert_arc(n1, n2);
192 g.insert_arc(n2, n3);
193 g.reset_nodes();
194 g.reset_arcs();
195
197 auto result = builder(g, n1);
198
199 EXPECT_EQ(result.get_num_nodes(), 3);
200 EXPECT_EQ(result.get_num_arcs(), 2);
201}
202
204{
205 [[maybe_unused]] auto n1 = g.insert_node(1);
206 auto n2 = g.insert_node(2);
207 auto n3 = g.insert_node(3);
208 g.insert_arc(n1, n2);
209 g.insert_arc(n2, n3);
210 g.reset_nodes();
211 g.reset_arcs();
212
213 DynList<Graph::Node*> node_list;
215 builder(g, node_list, n1);
216
217 EXPECT_EQ(node_list.size(), 3);
218}
219
221{
222 [[maybe_unused]] auto n1 = g.insert_node(1);
223
225
226 EXPECT_THROW(builder(g, sg, nullptr), std::invalid_argument);
227}
228
229//==============================================================================
230// Inconnected_Components Basic Tests
231//==============================================================================
232
234{
235 [[maybe_unused]] auto n1 = g.insert_node(1);
236 auto n2 = g.insert_node(2);
237 auto n3 = g.insert_node(3);
238 g.insert_arc(n1, n2);
239 g.insert_arc(n2, n3);
240
243 cc(g, components);
244
246 EXPECT_EQ(components.get_first().get_num_nodes(), 3);
247}
248
250{
251 // Component 1
252 [[maybe_unused]] auto n1 = g.insert_node(1);
253 auto n2 = g.insert_node(2);
254 g.insert_arc(n1, n2);
255
256 // Component 2 (disconnected)
257 auto n3 = g.insert_node(3);
258 auto n4 = g.insert_node(4);
259 g.insert_arc(n3, n4);
260
263 cc(g, components);
264
266
267 // Each component should have 2 nodes
268 size_t total_nodes = 0;
269 for (auto & comp : components)
270 total_nodes += comp.get_num_nodes();
272}
273
275{
276 // Three isolated nodes = three components
277 g.insert_node(1);
278 g.insert_node(2);
279 g.insert_node(3);
280
283 cc(g, components);
284
286}
287
296
298{
299 // Two components
300 [[maybe_unused]] auto n1 = g.insert_node(1);
301 auto n2 = g.insert_node(2);
302 g.insert_arc(n1, n2);
303
304 [[maybe_unused]] auto n3 = g.insert_node(3);
305
308 cc(g, node_lists);
309
311}
312
314{
315 [[maybe_unused]] auto n1 = g.insert_node(1);
316 auto n2 = g.insert_node(2);
317 g.insert_arc(n1, n2);
318
319 g.insert_node(3); // Isolated
320 g.insert_node(4); // Isolated
321
323
324 EXPECT_EQ(cc.count_components(g), 3);
325}
326
328{
329 [[maybe_unused]] auto n1 = g.insert_node(1);
330 auto n2 = g.insert_node(2);
331 auto n3 = g.insert_node(3);
332 g.insert_arc(n1, n2);
333 g.insert_arc(n2, n3);
334
336
337 EXPECT_TRUE(cc.is_connected(g));
338}
339
341{
342 [[maybe_unused]] auto n1 = g.insert_node(1);
343 auto n2 = g.insert_node(2);
344 g.insert_arc(n1, n2);
345
346 g.insert_node(3); // Isolated
347
349
350 EXPECT_FALSE(cc.is_connected(g));
351}
352
354{
356
357 EXPECT_TRUE(cc.is_connected(g)); // Empty graph is considered connected
358}
359
361{
362 g.insert_node(1);
363
365
366 EXPECT_TRUE(cc.is_connected(g));
367}
368
369//==============================================================================
370// Stress Tests
371//==============================================================================
372
374{
375 // Create 50 isolated nodes = 50 components
376 for (int i = 0; i < 50; ++i)
377 g.insert_node(i);
378
380
381 EXPECT_EQ(cc.count_components(g), 50);
382}
383
385{
386 const int N = 100;
388
389 for (int i = 0; i < N; ++i)
390 nodes.append(g.insert_node(i));
391
392 // Create a connected chain
393 for (int i = 0; i < N - 1; ++i)
394 g.insert_arc(nodes(i), nodes(i + 1));
395
397
398 EXPECT_TRUE(cc.is_connected(g));
399 EXPECT_EQ(cc.count_components(g), 1);
400}
401
402//==============================================================================
403// Typed Tests for All Graph Types
404//==============================================================================
405
406template <typename GraphType>
407class ComponentsAllGraphs : public ::testing::Test
408{
409protected:
411};
412
413using GraphTypes = ::testing::Types<
414 ListGraph,
420>;
421
423
424// Undirected graphs only - for connectivity tests
425// (Inconnected_Components is designed for undirected graphs)
426template <typename GraphType>
427class ComponentsUndirectedGraphs : public ::testing::Test
428{
429protected:
431};
432
433using UndirectedGraphTypes = ::testing::Types<
434 ListGraph,
437>;
438
440
442{
443 using Graph = TypeParam;
444 Graph & g = this->g;
445
446 [[maybe_unused]] auto n1 = g.insert_node(1);
447 g.reset_nodes();
448 g.reset_arcs();
449
450 Graph sg;
452 builder(g, sg, n1);
453
454 EXPECT_EQ(sg.get_num_nodes(), 1);
455 EXPECT_EQ(sg.get_num_arcs(), 0);
456}
457
459{
460 using Graph = TypeParam;
461 Graph & g = this->g;
462
463 [[maybe_unused]] auto n1 = g.insert_node(1);
464 auto n2 = g.insert_node(2);
465 auto n3 = g.insert_node(3);
466 g.insert_arc(n1, n2);
467 g.insert_arc(n2, n3);
468 g.insert_arc(n3, n1);
469 g.reset_nodes();
470 g.reset_arcs();
471
472 Graph sg;
474 builder(g, sg, n1);
475
476 EXPECT_EQ(sg.get_num_nodes(), 3);
477 EXPECT_EQ(sg.get_num_arcs(), 3);
478}
479
481{
482 using Graph = TypeParam;
483 Graph & g = this->g;
484
485 [[maybe_unused]] auto n1 = g.insert_node(1);
486
487 Graph sg;
489
490 EXPECT_THROW(builder(g, sg, nullptr), std::invalid_argument);
491}
492
494{
495 using Graph = TypeParam;
496 Graph & g = this->g;
497
498 [[maybe_unused]] auto n1 = g.insert_node(1);
499 auto n2 = g.insert_node(2);
500 auto n3 = g.insert_node(3);
501 g.insert_arc(n1, n2);
502 g.insert_arc(n2, n3);
503
506 cc(g, components);
507
509}
510
512{
513 using Graph = TypeParam;
514 Graph & g = this->g;
515
516 [[maybe_unused]] auto n1 = g.insert_node(1);
517 auto n2 = g.insert_node(2);
518 g.insert_arc(n1, n2);
519
520 auto n3 = g.insert_node(3);
521 auto n4 = g.insert_node(4);
522 g.insert_arc(n3, n4);
523
526 cc(g, components);
527
529}
530
532{
533 using Graph = TypeParam;
534 Graph & g = this->g;
535
536 g.insert_node(1);
537 g.insert_node(2);
538 g.insert_node(3);
539
541
542 EXPECT_EQ(cc.count_components(g), 3);
543}
544
546{
547 using Graph = TypeParam;
548 Graph & g = this->g;
549
550 [[maybe_unused]] auto n1 = g.insert_node(1);
551 auto n2 = g.insert_node(2);
552 g.insert_arc(n1, n2);
553
555
556 EXPECT_TRUE(cc.is_connected(g));
557}
558
560{
561 using Graph = TypeParam;
562 Graph & g = this->g;
563
564 [[maybe_unused]] auto n1 = g.insert_node(1);
565 auto n2 = g.insert_node(2);
566 g.insert_arc(n1, n2);
567
568 g.insert_node(3);
569
571
572 EXPECT_FALSE(cc.is_connected(g));
573}
574
576{
577 using Graph = TypeParam;
578 Graph & g = this->g;
579
581
582 EXPECT_TRUE(cc.is_connected(g));
583}
584
585// Main
586int main(int argc, char **argv)
587{
588 ::testing::InitGoogleTest(&argc, argv);
589 return RUN_ALL_TESTS();
590}
int main()
Build a mapped subgraph from a graph starting at a given node.
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
T & append()
Allocate a new entry to the end of array.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & get_first() const
Return the first item of the list.
Definition htlist.H:1675
Arc for graphs implemented with simple adjacency lists.
Definition tpl_sgraph.H:197
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
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
Compute the connected components of a graph.
void reset_arcs() const
Reset all the arcs of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:927
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
void reset_nodes() const
Reset all the nodes of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:920
#define N
Definition fib.C:294
::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.
Graph connectivity and connected components.
::testing::Types< ListGraph, ListDigraph, SparseGraph, SparseDigraph, ArrayGraph, ArrayDigraph > GraphTypes
TYPED_TEST(ComponentsAllGraphs, BuildSubgraphSingleNode)
List_Digraph< Graph_Node< int >, Graph_Arc< int > > ListDigraph
TYPED_TEST_SUITE(ComponentsAllGraphs, GraphTypes)
List_Graph< Graph_Node< int >, Graph_Arc< int > > ListGraph
Array_Graph< Graph_Anode< int >, Graph_Aarc< int > > ArrayGraph
List_SDigraph< Graph_Snode< int >, Graph_Sarc< int > > SparseDigraph
TEST_F(BuildSubgraphTest, SingleNode)
List_SGraph< Graph_Snode< int >, Graph_Sarc< int > > SparseGraph
Generic graph and digraph implementations.
Simple graph implementation with adjacency lists.