Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_agraph_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
33
38#include <gtest/gtest.h>
39#include <tpl_agraph.H>
40#include <string>
41
42using namespace Aleph;
43
44namespace
45{
46 // Type aliases for common graph types
50}
51
52// =============================================================================
53// Graph_Anode Tests
54// =============================================================================
55
57{
59 EXPECT_EQ(node.num_arcs, 0u);
60 EXPECT_EQ(node.arcs_dim, 0u);
61 EXPECT_EQ(node.arc_array, nullptr);
62}
63
65{
66 Graph_Anode<int> node(42);
67 EXPECT_EQ(node.get_info(), 42);
68 EXPECT_EQ(node.num_arcs, 0u);
69 EXPECT_GT(node.arcs_dim, 0u); // Should have default capacity
70}
71
73{
76 EXPECT_EQ(node2.get_info(), 42);
77 EXPECT_EQ(node2.num_arcs, 0u);
78}
79
81{
82 Graph_Anode<std::string> node1(std::string("test"));
84 EXPECT_EQ(node2.get_info(), "test");
85}
86
87// =============================================================================
88// Graph_Aarc Tests
89// =============================================================================
90
92{
94 EXPECT_EQ(arc.get_info(), 0); // Default int value
95}
96
98{
99 Graph_Aarc<int> arc(100);
100 EXPECT_EQ(arc.get_info(), 100);
101}
102
104{
105 Graph_Aarc<std::string> arc1(std::string("edge"));
106 Graph_Aarc<std::string> arc2(arc1);
107 EXPECT_EQ(arc2.get_info(), "edge");
108}
109
110// =============================================================================
111// Array_Graph Basic Operations
112// =============================================================================
113
115{
116 IntGraph g;
117 EXPECT_EQ(g.vsize(), 0u);
118 EXPECT_EQ(g.esize(), 0u);
120}
121
123{
124 IntGraph g;
125 auto n1 = g.insert_node(1);
126 auto n2 = g.insert_node(2);
127 auto n3 = g.insert_node(3);
128
129 EXPECT_EQ(g.vsize(), 3u);
130 EXPECT_EQ(n1->get_info(), 1);
131 EXPECT_EQ(n2->get_info(), 2);
132 EXPECT_EQ(n3->get_info(), 3);
133}
134
136{
137 IntGraph g;
138 auto n1 = g.insert_node(1);
139 auto n2 = g.insert_node(2);
140
141 auto arc = g.insert_arc(n1, n2, 10);
142
143 EXPECT_EQ(g.esize(), 1u);
144 EXPECT_EQ(arc->get_info(), 10);
145 EXPECT_EQ(g.get_src_node(arc), n1);
146 EXPECT_EQ(g.get_tgt_node(arc), n2);
147}
148
150{
151 IntGraph g;
152 auto n1 = g.insert_node(1);
153 auto n2 = g.insert_node(2);
154
155 g.insert_arc(n1, n2, 10);
156
157 // In undirected graph, arc appears in both nodes' adjacency lists
158 EXPECT_EQ(n1->num_arcs, 1u);
159 EXPECT_EQ(n2->num_arcs, 1u);
160}
161
163{
164 IntGraph g;
165 auto n1 = g.insert_node(1);
166 auto n2 = g.insert_node(2);
167 auto arc = g.insert_arc(n1, n2, 10);
168
169 EXPECT_EQ(g.esize(), 1u);
170 g.remove_arc(arc);
171 EXPECT_EQ(g.esize(), 0u);
172 EXPECT_EQ(n1->num_arcs, 0u);
173 EXPECT_EQ(n2->num_arcs, 0u);
174}
175
177{
178 IntGraph g;
179 auto n1 = g.insert_node(1);
180 auto n2 = g.insert_node(2);
181 auto n3 = g.insert_node(3);
182
183 g.insert_arc(n1, n2, 12);
184 g.insert_arc(n2, n3, 23);
185
186 EXPECT_EQ(g.vsize(), 3u);
187 EXPECT_EQ(g.esize(), 2u);
188
189 g.remove_node(n2);
190
191 EXPECT_EQ(g.vsize(), 2u);
192 EXPECT_EQ(g.esize(), 0u); // All arcs connected to n2 removed
193}
194
196{
197 IntGraph g;
198 auto n1 = g.insert_node(1);
199 auto n2 = g.insert_node(2);
200 auto n3 = g.insert_node(3);
201 auto n4 = g.insert_node(4);
202
203 g.insert_arc(n1, n2, 12);
204 g.insert_arc(n1, n3, 13);
205 g.insert_arc(n1, n4, 14);
206 g.insert_arc(n2, n3, 23);
207 g.insert_arc(n3, n4, 34);
208
209 EXPECT_EQ(g.esize(), 5u);
210 EXPECT_EQ(n1->num_arcs, 3u); // n1 connected to n2, n3, n4
211}
212
213// =============================================================================
214// Array_Digraph Tests
215// =============================================================================
216
218{
219 IntDigraph g;
220 EXPECT_TRUE(g.is_digraph());
221}
222
224{
225 IntDigraph g;
226 auto n1 = g.insert_node(1);
227 auto n2 = g.insert_node(2);
228
229 g.insert_arc(n1, n2, 10);
230
231 // In directed graph, arc only appears in source node's adjacency list
232 EXPECT_EQ(n1->num_arcs, 1u);
233 EXPECT_EQ(n2->num_arcs, 0u);
234}
235
237{
238 IntDigraph g;
239 auto n1 = g.insert_node(1);
240 auto n2 = g.insert_node(2);
241
242 g.insert_arc(n1, n2, 12);
243 g.insert_arc(n2, n1, 21);
244
245 EXPECT_EQ(g.esize(), 2u);
246 EXPECT_EQ(n1->num_arcs, 1u);
247 EXPECT_EQ(n2->num_arcs, 1u);
248}
249
250// =============================================================================
251// Iterator Tests
252// =============================================================================
253
255{
256 IntGraph g;
257 g.insert_node(1);
258 g.insert_node(2);
259 g.insert_node(3);
260
261 int count = 0;
262 int sum = 0;
263 for (IntGraph::Node_Iterator it(g); it.has_curr(); it.next())
264 {
265 sum += it.get_curr()->get_info();
266 ++count;
267 }
268
269 EXPECT_EQ(count, 3);
270 EXPECT_EQ(sum, 6); // 1 + 2 + 3
271}
272
274{
275 IntGraph g;
276 auto n1 = g.insert_node(1);
277 auto n2 = g.insert_node(2);
278 auto n3 = g.insert_node(3);
279
280 g.insert_arc(n1, n2, 10);
281 g.insert_arc(n2, n3, 20);
282
283 int count = 0;
284 int sum = 0;
285 for (IntGraph::Arc_Iterator it(g); it.has_curr(); it.next())
286 {
287 sum += it.get_curr()->get_info();
288 ++count;
289 }
290
291 EXPECT_EQ(count, 2);
292 EXPECT_EQ(sum, 30); // 10 + 20
293}
294
296{
297 IntGraph g;
298 auto n1 = g.insert_node(1);
299 auto n2 = g.insert_node(2);
300 auto n3 = g.insert_node(3);
301 auto n4 = g.insert_node(4);
302
303 g.insert_arc(n1, n2, 12);
304 g.insert_arc(n1, n3, 13);
305 g.insert_arc(n1, n4, 14);
306
307 int count = 0;
308 int sum = 0;
309 for (IntGraph::Node_Arc_Iterator it(n1); it.has_curr(); it.next())
310 {
311 sum += it.get_curr()->get_info();
312 ++count;
313 }
314
315 EXPECT_EQ(count, 3);
316 EXPECT_EQ(sum, 39); // 12 + 13 + 14
317}
318
319// =============================================================================
320// Copy and Move Semantics
321// =============================================================================
322
324{
325 IntGraph g1;
326 auto n1 = g1.insert_node(1);
327 auto n2 = g1.insert_node(2);
328 g1.insert_arc(n1, n2, 10);
329
330 IntGraph g2(g1);
331
332 EXPECT_EQ(g2.vsize(), 2u);
333 EXPECT_EQ(g2.esize(), 1u);
334}
335
337{
338 IntGraph g1;
339 g1.insert_node(1);
340 g1.insert_node(2);
341
342 IntGraph g2(std::move(g1));
343
344 EXPECT_EQ(g2.vsize(), 2u);
345 EXPECT_EQ(g1.vsize(), 0u); // Moved-from state
346}
347
349{
350 IntGraph g1;
351 auto n1 = g1.insert_node(1);
352 auto n2 = g1.insert_node(2);
353 g1.insert_arc(n1, n2, 10);
354
355 IntGraph g2;
356 g2 = g1;
357
358 EXPECT_EQ(g2.vsize(), 2u);
359 EXPECT_EQ(g2.esize(), 1u);
360}
361
363{
364 IntGraph g1;
365 g1.insert_node(1);
366 g1.insert_node(2);
367
368 IntGraph g2;
369 g2 = std::move(g1);
370
371 EXPECT_EQ(g2.vsize(), 2u);
372 EXPECT_EQ(g1.vsize(), 0u);
373}
374
376{
377 IntGraph g;
378 auto n1 = g.insert_node(1);
379 auto n2 = g.insert_node(2);
380 g.insert_arc(n1, n2, 10);
381
382 size_t orig_nodes = g.vsize();
383 size_t orig_arcs = g.esize();
384
385 g = g; // Self-assignment should be safe
386
389}
390
392{
393 IntGraph g;
394 auto n1 = g.insert_node(1);
395 auto n2 = g.insert_node(2);
396 g.insert_arc(n1, n2, 10);
397
398 IntGraph copy(g);
399
400 EXPECT_EQ(copy.vsize(), g.vsize());
401 EXPECT_EQ(copy.esize(), g.esize());
402
403 // Verify deep copy: modifying copy doesn't affect original
404 copy.insert_node(999);
405 EXPECT_NE(copy.vsize(), g.vsize());
406}
407
409{
410 IntGraph g;
411 auto n1 = g.insert_node(1);
412 auto n2 = g.insert_node(2);
413 g.insert_arc(n1, n2, 10);
414
415 // Create a non-empty target graph
417 for (int i = 0; i < 10; ++i)
418 target.insert_node(i * 100);
419
420 size_t orig_nodes = g.vsize();
421 size_t orig_arcs = g.esize();
422
423 // Copy should replace contents, not append
424 target = g;
425
426 EXPECT_EQ(target.vsize(), orig_nodes);
427 EXPECT_EQ(target.esize(), orig_arcs);
428}
429
430// =============================================================================
431// Sorting Tests
432// =============================================================================
433
435{
436 IntGraph g;
437 g.insert_node(3);
438 g.insert_node(1);
439 g.insert_node(2);
440
441 g.sort_nodes([](auto *a, auto *b) {
442 return a->get_info() < b->get_info();
443 });
444
445 std::vector<int> values;
446 for (IntGraph::Node_Iterator it(g); it.has_curr(); it.next())
447 values.push_back(it.get_curr()->get_info());
448
449 EXPECT_EQ(values, (std::vector<int>{1, 2, 3}));
450}
451
453{
454 IntGraph g;
455 auto n1 = g.insert_node(1);
456 auto n2 = g.insert_node(2);
457
458 g.insert_arc(n1, n2, 30);
459 g.insert_arc(n1, n2, 10);
460 g.insert_arc(n1, n2, 20);
461
462 g.sort_arcs([](auto *a, auto *b) {
463 return a->get_info() < b->get_info();
464 });
465
466 std::vector<int> values;
467 for (IntGraph::Arc_Iterator it(g); it.has_curr(); it.next())
468 values.push_back(it.get_curr()->get_info());
469
470 EXPECT_EQ(values, (std::vector<int>{10, 20, 30}));
471}
472
473// =============================================================================
474// Stress Tests
475// =============================================================================
476
478{
479 IntGraph g;
480 constexpr int N = 100;
481
482 // Insert N nodes
483 std::vector<IntGraph::Node*> nodes;
484 for (int i = 0; i < N; ++i)
485 nodes.push_back(g.insert_node(i));
486
487 EXPECT_EQ(g.vsize(), static_cast<size_t>(N));
488
489 // Create a complete graph (N*(N-1)/2 edges)
490 for (int i = 0; i < N; ++i)
491 for (int j = i + 1; j < N; ++j)
492 g.insert_arc(nodes[i], nodes[j], i * N + j);
493
494 EXPECT_EQ(g.esize(), static_cast<size_t>(N * (N - 1) / 2));
495}
496
498{
499 IntDigraph g;
500 constexpr int N = 50;
501
502 std::vector<IntDigraph::Node*> nodes;
503 for (int i = 0; i < N; ++i)
504 nodes.push_back(g.insert_node(i));
505
506 // Create complete digraph (N*(N-1) edges)
507 for (int i = 0; i < N; ++i)
508 for (int j = 0; j < N; ++j)
509 if (i != j)
510 g.insert_arc(nodes[i], nodes[j], i * N + j);
511
512 EXPECT_EQ(g.esize(), static_cast<size_t>(N * (N - 1)));
513}
514
515// =============================================================================
516// Edge Cases
517// =============================================================================
518
520{
521 IntGraph g;
522 auto n1 = g.insert_node(1);
523
524 auto arc = g.insert_arc(n1, n1, 11);
525
526 EXPECT_EQ(g.esize(), 1u);
527 EXPECT_EQ(n1->num_arcs, 1u); // Self-loop counted once
528 EXPECT_EQ(g.get_src_node(arc), n1);
529 EXPECT_EQ(g.get_tgt_node(arc), n1);
530}
531
533{
534 IntGraph g;
535 auto n1 = g.insert_node(1);
536 auto n2 = g.insert_node(2);
537
538 auto arc = g.insert_arc(n1, n2, 10);
539 EXPECT_EQ(g.esize(), 1u);
540
541 g.disconnect_arc(arc);
542 EXPECT_EQ(g.esize(), 0u);
543 EXPECT_EQ(n1->num_arcs, 0u);
544
545 g.connect_arc(arc);
546 EXPECT_EQ(g.esize(), 1u);
547 EXPECT_EQ(n1->num_arcs, 1u);
548
549 // Clean up the arc we disconnected/reconnected
550 g.remove_arc(arc);
551}
552
554{
555 IntGraph g;
556
557 int node_count = 0;
558 for (IntGraph::Node_Iterator it(g); it.has_curr(); it.next())
559 ++node_count;
560 EXPECT_EQ(node_count, 0);
561
562 int arc_count = 0;
563 for (IntGraph::Arc_Iterator it(g); it.has_curr(); it.next())
564 ++arc_count;
566}
567
569{
570 IntGraph g;
571 auto n1 = g.insert_node(1);
572 auto n2 = g.insert_node(2);
573 auto arc = g.insert_arc(n1, n2, 10);
574
575 EXPECT_NE(g.get_first_node(), nullptr);
576 EXPECT_NE(g.get_first_arc(), nullptr);
577 EXPECT_EQ(g.get_first_arc(n1), arc);
578}
579
580// =============================================================================
581// String Data Type Tests
582// =============================================================================
583
585{
586 StringGraph g;
587 auto n1 = g.insert_node(std::string("node1"));
588 auto n2 = g.insert_node(std::string("node2"));
589
590 g.insert_arc(n1, n2, std::string("edge"));
591
592 EXPECT_EQ(n1->get_info(), "node1");
593 EXPECT_EQ(n2->get_info(), "node2");
594}
595
596// =============================================================================
597// Digraph Template Wrapper Tests (Array_Digraph)
598// =============================================================================
599
600// These tests validate the generic Digraph<BaseGraph> template wrapper
601// works correctly with Array_Graph as the base.
602
604{
605 IntDigraph dg;
606
607 auto n1 = dg.insert_node(1);
608 auto n2 = dg.insert_node(2);
609 auto arc = dg.insert_arc(n1, n2, 100);
610
611 EXPECT_EQ(dg.vsize(), 2u);
612 EXPECT_EQ(dg.esize(), 1u);
613 EXPECT_TRUE(dg.is_digraph());
614 EXPECT_EQ(dg.get_src_node(arc), n1);
615 EXPECT_EQ(dg.get_tgt_node(arc), n2);
616}
617
619{
621 dg1.insert_node(1);
622 dg1.insert_node(2);
623
625 EXPECT_TRUE(dg2.is_digraph());
626 EXPECT_EQ(dg2.vsize(), 2u);
627}
628
630{
632 dg1.insert_node(1);
633 dg1.insert_node(2);
634
635 IntDigraph dg2(std::move(dg1));
636 EXPECT_TRUE(dg2.is_digraph());
637 EXPECT_EQ(dg2.vsize(), 2u);
638}
639
641{
643 dg1.insert_node(1);
644
646 dg2.insert_node(10);
647
648 dg2 = dg1;
649 EXPECT_TRUE(dg2.is_digraph());
650 EXPECT_EQ(dg2.vsize(), 1u);
651}
652
654{
656 dg1.insert_node(1);
657
659 dg2 = std::move(dg1);
660 EXPECT_TRUE(dg2.is_digraph());
661 EXPECT_EQ(dg2.vsize(), 1u);
662}
663
664// =============================================================================
665// C++20 Concepts Tests
666// =============================================================================
667
668// Compile-time verification that Array_Graph iterators satisfy concepts
670 "Array_Graph::Node_Iterator must satisfy BasicGraphIterator");
672 "Array_Graph::Arc_Iterator must satisfy BasicGraphIterator");
674 "Array_Graph::Node_Iterator must satisfy GraphNodeIterator");
676 "Array_Graph::Arc_Iterator must satisfy GraphArcIterator");
677
679{
680 IntGraph g;
681 auto n1 = g.insert_node(1);
682 auto n2 = g.insert_node(2);
683 g.insert_arc(n1, n2, 10);
684
685 // Verify node iterator works per concept
686 auto nit = g.get_node_it();
687 EXPECT_TRUE(nit.has_curr());
688 EXPECT_NE(nit.get_curr(), nullptr);
689
690 // Verify arc iterator works per concept
691 auto ait = g.get_arc_it();
692 EXPECT_TRUE(ait.has_curr());
693 EXPECT_NE(ait.get_curr(), nullptr);
694}
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
Node of Array_Graph
Definition tpl_agraph.H:64
Node * get_first_node() const
Return any node in the graph.
Definition tpl_graph.H:576
Arc * get_first_arc(Node *node) const
Return any arc adjacent to a node.
Definition tpl_graph.H:595
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
virtual void remove_node(Node *node) noexcept
Remove a node from the graph and free its memory.
Definition tpl_graph.H:543
virtual Arc * connect_arc(Arc *arc) noexcept
Connect a previously disconnected arc to the graph.
Definition tpl_graph.H:733
virtual void remove_arc(Arc *arc) noexcept
Remove an arc from the graph and free it.
Definition tpl_graph.H:649
virtual void disconnect_arc(Arc *arc) noexcept
Disconnect an arc from graph.
Definition tpl_graph.H:699
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
ArcInfo & get_info() noexcept
Return a modifiable reference to the arc data.
Definition graph-dry.H:595
NodeInfo & get_info() noexcept
Return a modifiable reference to the data contained in the node.
Definition graph-dry.H:494
size_t num_arcs
data associated to the node. Access it with get_info()
Definition graph-dry.H:454
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Definition graph-dry.H:2802
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:731
bool is_digraph() const noexcept
Return true if the graph this is directed.
Definition graph-dry.H:657
void sort_arcs(Compare &cmp) noexcept
Sort all the arcs of the graph according to a specific criteria.
Definition graph-dry.H:3736
constexpr size_t vsize() const noexcept
Definition graph-dry.H:698
size_t esize() const noexcept
Return the total of arcs of graph.
Definition graph-dry.H:792
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2780
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:737
void sort_nodes(Compare &cmp) noexcept
Definition graph-dry.H:3702
Concept for basic graph iterators.
Definition graph-dry.H:152
Concept for graph arc iterators.
Definition graph-dry.H:210
Concept for graph node iterators.
Definition graph-dry.H:191
Concept for node adjacency iterators.
Definition graph-dry.H:234
#define TEST(name)
#define N
Definition fib.C:294
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Array-based graph implementation.