Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_graph_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
47#include <gtest/gtest.h>
48#include <vector>
49#include <algorithm>
50#include <random>
51#include <string>
52#include <tpl_graph.H>
53
54using namespace std;
55using namespace testing;
56using namespace Aleph;
57
58// =============================================================================
59// Type Definitions
60// =============================================================================
61
65
66// =============================================================================
67// Graph_Node Tests
68// =============================================================================
69
76
82
89
91{
92 Graph_Node<string> node1(string("test"));
93 Graph_Node<string> node2(std::move(node1));
94 EXPECT_EQ(node2.get_info(), "test");
95}
96
98{
101 node2 = node1;
102 EXPECT_EQ(node2.get_info(), 42);
103}
104
106{
107 Graph_Node<int> node(42);
108 node = node;
109 EXPECT_EQ(node.get_info(), 42);
110}
111
118
119// =============================================================================
120// Graph_Arc Tests
121// =============================================================================
122
128
130{
131 Graph_Arc<double> arc(3.14);
132 EXPECT_EQ(arc.get_info(), 3.14);
133}
134
136{
137 Graph_Arc<double> arc1(3.14);
138 Graph_Arc<double> arc2(arc1);
139 EXPECT_EQ(arc2.get_info(), 3.14);
140}
141
143{
144 Graph_Arc<double> arc1(3.14);
145 Graph_Arc<double> arc2(1.0);
146 arc2 = arc1;
147 EXPECT_EQ(arc2.get_info(), 3.14);
148}
149
151{
152 Graph_Arc<double> arc(3.14);
153 arc = arc;
154 EXPECT_EQ(arc.get_info(), 3.14);
155}
156
157// =============================================================================
158// Basic Graph Construction Tests
159// =============================================================================
160
161class GraphBasicTest : public Test
162{
163protected:
166};
167
169{
170 EXPECT_EQ(g.get_num_nodes(), 0);
171 EXPECT_EQ(g.get_num_arcs(), 0);
172 EXPECT_FALSE(g.is_digraph());
173}
174
176{
177 EXPECT_EQ(dg.get_num_nodes(), 0);
178 EXPECT_EQ(dg.get_num_arcs(), 0);
179 EXPECT_TRUE(dg.is_digraph());
180}
181
183{
184 auto n = g.insert_node(10);
185 EXPECT_NE(n, nullptr);
186 EXPECT_EQ(n->get_info(), 10);
187 EXPECT_EQ(g.get_num_nodes(), 1);
188 EXPECT_EQ(g.get_num_arcs(), 0);
189}
190
192{
193 vector<Graph::Node*> nodes;
194 for (int i = 0; i < 100; ++i)
195 nodes.push_back(g.insert_node(i));
196
197 EXPECT_EQ(g.get_num_nodes(), 100);
198 for (int i = 0; i < 100; ++i)
199 EXPECT_EQ(nodes[i]->get_info(), i);
200}
201
203{
204 auto n1 = g.insert_node(1);
205 auto n2 = g.insert_node(2);
206 auto a = g.insert_arc(n1, n2, 1.5);
207
208 EXPECT_NE(a, nullptr);
209 EXPECT_EQ(a->get_info(), 1.5);
210 EXPECT_EQ(g.get_num_arcs(), 1);
211 EXPECT_EQ(g.get_src_node(a), n1);
212 EXPECT_EQ(g.get_tgt_node(a), n2);
213}
214
216{
217 auto n = g.insert_node(1);
218 auto a = g.insert_arc(n, n, 0.0);
219
220 EXPECT_NE(a, nullptr);
221 EXPECT_EQ(g.get_num_arcs(), 1);
222 EXPECT_EQ(g.get_src_node(a), n);
223 EXPECT_EQ(g.get_tgt_node(a), n);
224}
225
226// =============================================================================
227// Node Removal Tests
228// =============================================================================
229
230class GraphNodeRemovalTest : public Test
231{
232protected:
234
235 void SetUp() override
236 {
237 for (int i = 0; i < 5; ++i)
238 g.insert_node(i);
239 }
240};
241
243{
244 auto n = g.get_first_node();
245 g.remove_node(n);
246 EXPECT_EQ(g.get_num_nodes(), 4);
247}
248
250{
251 vector<Graph::Node*> nodes;
252 for (auto it = g.get_node_it(); it.has_curr(); it.next())
253 nodes.push_back(it.get_curr());
254
255 g.insert_arc(nodes[0], nodes[1], 1.0);
256 g.insert_arc(nodes[0], nodes[2], 2.0);
257 g.insert_arc(nodes[1], nodes[2], 3.0);
258
259 EXPECT_EQ(g.get_num_arcs(), 3);
260 g.remove_node(nodes[0]);
261 EXPECT_EQ(g.get_num_nodes(), 4);
262 EXPECT_EQ(g.get_num_arcs(), 1);
263}
264
266{
267 while (g.get_num_nodes() > 0)
268 g.remove_node(g.get_first_node());
269
270 EXPECT_EQ(g.get_num_nodes(), 0);
271 EXPECT_EQ(g.get_num_arcs(), 0);
272}
273
274// =============================================================================
275// Arc Removal Tests
276// =============================================================================
277
278class GraphArcRemovalTest : public Test
279{
280protected:
284
285 void SetUp() override
286 {
287 n1 = g.insert_node(1);
288 n2 = g.insert_node(2);
289 n3 = g.insert_node(3);
290 a1 = g.insert_arc(n1, n2, 1.0);
291 a2 = g.insert_arc(n2, n3, 2.0);
292 a3 = g.insert_arc(n1, n3, 3.0);
293 }
294};
295
297{
298 g.remove_arc(a1);
299 EXPECT_EQ(g.get_num_arcs(), 2);
300 EXPECT_EQ(g.get_num_nodes(), 3);
301}
302
304{
305 g.remove_arc(a1);
306 g.remove_arc(a2);
307 g.remove_arc(a3);
308 EXPECT_EQ(g.get_num_arcs(), 0);
309 EXPECT_EQ(g.get_num_nodes(), 3);
310}
311
313{
314 g.disconnect_arc(a1);
315 EXPECT_EQ(g.get_num_arcs(), 2);
316
317 g.connect_arc(a1);
318 EXPECT_EQ(g.get_num_arcs(), 3);
319 // Note: do not delete a1 here - the graph destructor will handle it
320}
321
322// =============================================================================
323// Iterator Tests
324// =============================================================================
325
326class GraphIteratorTest : public Test
327{
328protected:
330 vector<Graph::Node*> nodes;
331 vector<Graph::Arc*> arcs;
332
333 void SetUp() override
334 {
335 for (int i = 0; i < 5; ++i)
336 nodes.push_back(g.insert_node(i * 10));
337
338 arcs.push_back(g.insert_arc(nodes[0], nodes[1], 0.1));
339 arcs.push_back(g.insert_arc(nodes[1], nodes[2], 0.2));
340 arcs.push_back(g.insert_arc(nodes[2], nodes[3], 0.3));
341 arcs.push_back(g.insert_arc(nodes[3], nodes[4], 0.4));
342 arcs.push_back(g.insert_arc(nodes[4], nodes[0], 0.5));
343 }
344};
345
347{
348 size_t count = 0;
349 for (auto it = g.get_node_it(); it.has_curr(); it.next())
350 ++count;
351
352 EXPECT_EQ(count, 5);
353}
354
356{
357 size_t count = 0;
358 for (auto it = g.get_arc_it(); it.has_curr(); it.next())
359 ++count;
360
361 EXPECT_EQ(count, 5);
362}
363
365{
366 size_t count = 0;
367 for (auto it = g.get_arc_it(nodes[0]); it.has_curr(); it.next())
368 ++count;
369
370 EXPECT_EQ(count, 2);
371}
372
374{
375 auto it = g.get_node_it();
376 it.next();
377 it.next();
378 it.reset_first();
379 EXPECT_TRUE(it.has_curr());
380}
381
383{
384 auto it = g.get_node_it();
385 it.reset_last();
386 EXPECT_TRUE(it.has_curr());
387}
388
389// =============================================================================
390// Filtered Iterator Tests
391// =============================================================================
392
394{
395 bool operator()(Graph::Node *n) const noexcept
396 {
397 return n->get_info() % 20 == 0;
398 }
399};
400
402{
403 bool operator()(Graph::Arc *a) const noexcept
404 {
405 return a->get_info() > 0.25;
406 }
407};
408
410{
411 size_t count = 0;
412 for (Node_Iterator<Graph, EvenNodeFilter> it(g); it.has_curr(); it.next())
413 ++count;
414
415 EXPECT_EQ(count, 3);
416}
417
419{
420 size_t count = 0;
421 for (Arc_Iterator<Graph, HighWeightArcFilter> it(g); it.has_curr(); it.next())
422 ++count;
423
424 EXPECT_EQ(count, 3);
425}
426
427// =============================================================================
428// Search Tests
429// =============================================================================
430
432{
433 auto arc = search_arc(g, nodes[0], nodes[1]);
434 EXPECT_NE(arc, nullptr);
435 EXPECT_EQ(arc->get_info(), 0.1);
436}
437
439{
440 auto arc = search_arc(g, nodes[0], nodes[2]);
441 EXPECT_EQ(arc, nullptr);
442}
443
445{
446 auto arc = search_directed_arc(g, nodes[0], nodes[1]);
447 EXPECT_NE(arc, nullptr);
448}
449
450// =============================================================================
451// Graph Move Tests (Copy tests removed due to linker dependencies)
452// =============================================================================
453
454class GraphMoveTest : public Test
455{
456protected:
458
459 void SetUp() override
460 {
461 auto n1 = g.insert_node(1);
462 auto n2 = g.insert_node(2);
463 auto n3 = g.insert_node(3);
464 g.insert_arc(n1, n2, 1.0);
465 g.insert_arc(n2, n3, 2.0);
466 }
467};
468
470{
471 size_t orig_nodes = g.get_num_nodes();
472 size_t orig_arcs = g.get_num_arcs();
473
474 Graph moved(std::move(g));
475 EXPECT_EQ(moved.get_num_nodes(), orig_nodes);
476 EXPECT_EQ(moved.get_num_arcs(), orig_arcs);
477 EXPECT_EQ(g.get_num_nodes(), 0);
478 EXPECT_EQ(g.get_num_arcs(), 0);
479}
480
482{
483 size_t orig_nodes = g.get_num_nodes();
484 size_t orig_arcs = g.get_num_arcs();
485
486 Graph moved;
487 moved = std::move(g);
488 EXPECT_EQ(moved.get_num_nodes(), orig_nodes);
489 EXPECT_EQ(moved.get_num_arcs(), orig_arcs);
490}
491
493{
494 Graph g2;
495 auto n = g2.insert_node(100);
496 g2.insert_arc(n, n, 0.5);
497
498 size_t g1_nodes = g.get_num_nodes();
499 size_t g2_nodes = g2.get_num_nodes();
500
501 g.swap(g2);
502
503 EXPECT_EQ(g.get_num_nodes(), g2_nodes);
504 EXPECT_EQ(g2.get_num_nodes(), g1_nodes);
505}
506
508{
509 size_t orig_nodes = g.get_num_nodes();
510 size_t orig_arcs = g.get_num_arcs();
511
512 g = g; // Self-assignment should be safe
513
514 EXPECT_EQ(g.get_num_nodes(), orig_nodes);
515 EXPECT_EQ(g.get_num_arcs(), orig_arcs);
516}
517
519{
520 Graph copy(g);
521
522 EXPECT_EQ(copy.get_num_nodes(), g.get_num_nodes());
523 EXPECT_EQ(copy.get_num_arcs(), g.get_num_arcs());
524
525 // Verify deep copy: modifying copy doesn't affect original
526 auto n = copy.insert_node(999);
527 copy.insert_arc(n, n, 99.0);
528 EXPECT_NE(copy.get_num_nodes(), g.get_num_nodes());
529 EXPECT_NE(copy.get_num_arcs(), g.get_num_arcs());
530}
531
533{
534 Graph copy;
535 copy = g;
536
537 EXPECT_EQ(copy.get_num_nodes(), g.get_num_nodes());
538 EXPECT_EQ(copy.get_num_arcs(), g.get_num_arcs());
539}
540
542{
543 // Create a non-empty target graph
545 for (int i = 0; i < 10; ++i)
546 target.insert_node(i * 100);
547
548 size_t orig_nodes = g.get_num_nodes();
549 size_t orig_arcs = g.get_num_arcs();
550
551 // Copy should replace contents, not append
552 target = g;
553
554 EXPECT_EQ(target.get_num_nodes(), orig_nodes);
555 EXPECT_EQ(target.get_num_arcs(), orig_arcs);
556}
557
558// =============================================================================
559// Path Tests
560// =============================================================================
561
562class PathTest : public Test
563{
564protected:
566 vector<Graph::Node*> nodes;
567 vector<Graph::Arc*> arcs;
568
569 void SetUp() override
570 {
571 for (int i = 0; i < 5; ++i)
572 nodes.push_back(g.insert_node(i));
573
574 arcs.push_back(g.insert_arc(nodes[0], nodes[1], 0.1));
575 arcs.push_back(g.insert_arc(nodes[1], nodes[2], 0.2));
576 arcs.push_back(g.insert_arc(nodes[2], nodes[3], 0.3));
577 arcs.push_back(g.insert_arc(nodes[3], nodes[4], 0.4));
578 }
579};
580
582{
583 Path<Graph> path(g);
584 EXPECT_TRUE(path.is_empty());
585 EXPECT_EQ(path.size(), 0);
586}
587
589{
590 Path<Graph> path(g, nodes[0]);
591 EXPECT_FALSE(path.is_empty());
592 EXPECT_EQ(path.size(), 1);
593 EXPECT_EQ(path.get_first_node(), nodes[0]);
594 EXPECT_EQ(path.get_last_node(), nodes[0]);
595}
596
598{
599 Path<Graph> path(g, nodes[0]);
600 path.append(arcs[0]);
601 EXPECT_EQ(path.size(), 2);
602 EXPECT_EQ(path.get_first_node(), nodes[0]);
603 EXPECT_EQ(path.get_last_node(), nodes[1]);
604}
605
607{
608 Path<Graph> path(g, nodes[0]);
609 path.append(nodes[1]);
610 EXPECT_EQ(path.size(), 2);
611 EXPECT_EQ(path.get_last_node(), nodes[1]);
612}
613
615{
616 Path<Graph> path(g, nodes[1]);
617 path.insert(arcs[0]);
618 EXPECT_EQ(path.size(), 2);
619 EXPECT_EQ(path.get_first_node(), nodes[0]);
620}
621
623{
624 Path<Graph> path(g, nodes[1]);
625 path.insert(nodes[0]);
626 EXPECT_EQ(path.size(), 2);
627 EXPECT_EQ(path.get_first_node(), nodes[0]);
628}
629
631{
632 Path<Graph> path(g, nodes[0]);
633 for (size_t i = 0; i < arcs.size(); ++i)
634 path.append(arcs[i]);
635
636 EXPECT_EQ(path.size(), 5);
637 EXPECT_EQ(path.get_first_node(), nodes[0]);
638 EXPECT_EQ(path.get_last_node(), nodes[4]);
639}
640
642{
643 Path<Graph> path(g, nodes[0]);
644 path.append(arcs[0]);
645 path.append(arcs[1]);
646
651}
652
654{
655 Path<Graph> path(g, nodes[0]);
656 path.append(arcs[0]);
657 path.append(arcs[1]);
658
659 EXPECT_TRUE(path.contains_arc(arcs[0]));
660 EXPECT_TRUE(path.contains_arc(arcs[1]));
662}
663
665{
666 Path<Graph> path(g, nodes[0]);
667 path.append(arcs[0]);
668 path.append(arcs[1]);
669
670 size_t node_count = 0;
671 for (typename Path<Graph>::Iterator it(path); it.has_current_node(); it.next())
672 ++node_count;
673
674 EXPECT_EQ(node_count, 3);
675}
676
678{
679 Path<Graph> path(g, nodes[0]);
680 path.append(arcs[0]);
681 path.append(arcs[1]);
682
683 auto node_list = path.nodes();
684 EXPECT_EQ(node_list.size(), 3);
685}
686
688{
689 Path<Graph> path(g, nodes[0]);
690 path.append(arcs[0]);
691 path.append(arcs[1]);
692
693 auto arc_list = path.arcs();
694 EXPECT_EQ(arc_list.size(), 2);
695}
696
698{
699 Path<Graph> path(g, nodes[0]);
700 path.append(arcs[0]);
701 path.append(arcs[1]);
702
703 Path<Graph> copy(path);
704 EXPECT_EQ(copy.size(), path.size());
705}
706
708{
709 Path<Graph> path(g, nodes[0]);
710 path.append(arcs[0]);
711 path.append(arcs[1]);
712
713 size_t orig_size = path.size();
714 Path<Graph> moved(std::move(path));
716}
717
719{
720 Path<Graph> path(g, nodes[0]);
721 path.append(arcs[0]);
722 path.append(arcs[1]);
723
724 auto removed = path.remove_last_node();
726 EXPECT_EQ(path.size(), 2);
727}
728
730{
731 Path<Graph> path(g, nodes[0]);
732 path.append(arcs[0]);
733 path.append(arcs[1]);
734
735 auto removed = path.remove_first_node();
737 EXPECT_EQ(path.size(), 2);
738}
739
741{
742 auto loop_arc = g.insert_arc(nodes[4], nodes[0], 0.5);
743
744 Path<Graph> path(g, nodes[0]);
745 for (auto a : arcs)
746 path.append(a);
747 path.append(loop_arc);
748
749 EXPECT_TRUE(path.is_cycle());
750}
751
753{
754 Path<Graph> path(g, nodes[0]);
755 path.append(arcs[0]);
756 path.append(arcs[1]);
757
758 EXPECT_FALSE(path.is_cycle());
759}
760
761// =============================================================================
762// Directed Path Tests
763// =============================================================================
764
765class DirectedPathTest : public Test
766{
767protected:
769 vector<TestDigraph::Node*> nodes;
770 vector<TestDigraph::Arc*> arcs;
771
772 void SetUp() override
773 {
774 for (int i = 0; i < 5; ++i)
775 nodes.push_back(dg.insert_node(i));
776
777 arcs.push_back(dg.insert_arc(nodes[0], nodes[1], 0.1));
778 arcs.push_back(dg.insert_arc(nodes[1], nodes[2], 0.2));
779 arcs.push_back(dg.insert_arc(nodes[2], nodes[3], 0.3));
780 arcs.push_back(dg.insert_arc(nodes[3], nodes[4], 0.4));
781 }
782};
783
785{
786 Path<TestDigraph> path(dg, nodes[0]);
787 path.append_directed(nodes[1]);
788 EXPECT_EQ(path.size(), 2);
789 EXPECT_EQ(path.get_last_node(), nodes[1]);
790}
791
793{
794 Path<TestDigraph> path(dg, nodes[0]);
795 path.append_directed(arcs[0]);
796 EXPECT_EQ(path.size(), 2);
797 EXPECT_EQ(path.get_last_node(), nodes[1]);
798}
799
801{
802 Path<TestDigraph> path(dg, nodes[1]);
803 path.insert_directed(nodes[0]);
804 EXPECT_EQ(path.size(), 2);
805 EXPECT_EQ(path.get_first_node(), nodes[0]);
806}
807
809{
810 Path<TestDigraph> path(dg, nodes[1]);
811 path.insert_directed(arcs[0]);
812 EXPECT_EQ(path.size(), 2);
813 EXPECT_EQ(path.get_first_node(), nodes[0]);
814}
815
816// =============================================================================
817// Exception Tests
818// =============================================================================
819
820class GraphExceptionTest : public Test
821{
822protected:
824};
825
827{
828 EXPECT_THROW(g.get_first_node(), std::range_error);
829}
830
832{
833 g.insert_node(1);
834 EXPECT_THROW(g.get_first_arc(), std::range_error);
835}
836
838{
839 auto n1 = g.insert_node(1);
840 auto n2 = g.insert_node(2);
841 auto a = g.insert_arc(n1, n2, 1.0);
842
843 Path<Graph> path(g);
844 EXPECT_THROW(path.append(a), std::domain_error);
845}
846
848{
849 auto n1 = g.insert_node(1);
850 auto n2 = g.insert_node(2);
851 auto n3 = g.insert_node(3);
852 auto a = g.insert_arc(n2, n3, 1.0);
853
854 Path<Graph> path(g, n1);
855 EXPECT_THROW(path.append(a), std::invalid_argument);
856}
857
859{
860 auto n1 = g.insert_node(1);
861 auto n2 = g.insert_node(2);
862 auto a = g.insert_arc(n1, n2, 1.0);
863
864 Path<Graph> path(g);
865 EXPECT_THROW(path.insert(a), std::domain_error);
866}
867
868// =============================================================================
869// Digraph-specific Tests
870// =============================================================================
871
872class DigraphTest : public Test
873{
874protected:
876 vector<TestDigraph::Node*> nodes;
877 vector<TestDigraph::Arc*> arcs;
878
879 void SetUp() override
880 {
881 for (int i = 0; i < 4; ++i)
882 nodes.push_back(dg.insert_node(i));
883
884 arcs.push_back(dg.insert_arc(nodes[0], nodes[1], 1.0));
885 arcs.push_back(dg.insert_arc(nodes[1], nodes[2], 2.0));
886 arcs.push_back(dg.insert_arc(nodes[2], nodes[3], 3.0));
887 arcs.push_back(dg.insert_arc(nodes[0], nodes[2], 4.0));
888 }
889};
890
892{
893 // Count outgoing arcs manually
894 size_t out_count_0 = 0;
895 for (auto it = dg.get_arc_it(nodes[0]); it.has_curr(); it.next())
896 if (dg.get_src_node(it.get_curr()) == nodes[0])
897 ++out_count_0;
899
900 // Node 3 has no outgoing arcs
901 size_t out_count_3 = 0;
902 for (auto it = dg.get_arc_it(nodes[3]); it.has_curr(); it.next())
903 if (dg.get_src_node(it.get_curr()) == nodes[3])
904 ++out_count_3;
906}
907
909{
910 size_t count = 0;
911 for (auto it = dg.get_arc_it(nodes[0]); it.has_curr(); it.next())
912 ++count;
913
914 EXPECT_EQ(count, 2);
915}
916
918{
919 // Verify arc direction
920 EXPECT_EQ(dg.get_src_node(arcs[0]), nodes[0]);
921 EXPECT_EQ(dg.get_tgt_node(arcs[0]), nodes[1]);
922}
923
924// =============================================================================
925// Functional Operations Tests
926// =============================================================================
927
928class GraphFunctionalTest : public Test
929{
930protected:
932 vector<Graph::Node*> nodes;
933
934 void SetUp() override
935 {
936 for (int i = 1; i <= 5; ++i)
937 nodes.push_back(g.insert_node(i * 10));
938
939 g.insert_arc(nodes[0], nodes[1], 1.0);
940 g.insert_arc(nodes[1], nodes[2], 2.0);
941 g.insert_arc(nodes[2], nodes[3], 3.0);
942 g.insert_arc(nodes[3], nodes[4], 4.0);
943 }
944};
945
947{
948 int sum = 0;
949 for_each_node<Graph>(g, [&sum](Graph::Node *n) { sum += n->get_info(); });
950 EXPECT_EQ(sum, 150);
951}
952
954{
955 double sum = 0;
956 for_each_arc<Graph>(g, [&sum](Graph::Arc *a) { sum += a->get_info(); });
957 EXPECT_EQ(sum, 10.0);
958}
959
961{
963 return n->get_info() > 0;
964 });
966}
967
969{
970 bool all_positive = forall_arc<Graph>(g, [](Graph::Arc *a) {
971 return a->get_info() > 0;
972 });
974}
975
977{
978 int sum = foldl_nodes<Graph, int>(g, 0, [](const int & acc, Graph::Node *n) {
979 return acc + n->get_info();
980 });
981 EXPECT_EQ(sum, 150);
982}
983
985{
986 double sum = foldl_arcs<Graph, double>(g, 0.0, [](const double & acc, Graph::Arc *a) {
987 return acc + a->get_info();
988 });
989 EXPECT_EQ(sum, 10.0);
990}
991
992// =============================================================================
993// Find Path Tests
994// =============================================================================
995
997{
998 auto path = find_path_depth_first(g, nodes[0], nodes[4]);
999 EXPECT_FALSE(path.is_empty());
1000 EXPECT_EQ(path.get_first_node(), nodes[0]);
1001 EXPECT_EQ(path.get_last_node(), nodes[4]);
1002}
1003
1005{
1006 Graph g2;
1007 auto n1 = g2.insert_node(1);
1008 auto n2 = g2.insert_node(2);
1009
1010 auto path = find_path_depth_first(g2, n1, n2);
1011 EXPECT_TRUE(path.is_empty());
1012}
1013
1014// =============================================================================
1015// Stress Tests
1016// =============================================================================
1017
1018class GraphStressTest : public Test
1019{
1020protected:
1022 static constexpr size_t NUM_NODES = 1000;
1023 static constexpr size_t NUM_ARCS = 5000;
1024};
1025
1027{
1028 for (size_t i = 0; i < NUM_NODES; ++i)
1029 g.insert_node(static_cast<int>(i));
1030
1031 EXPECT_EQ(g.get_num_nodes(), NUM_NODES);
1032}
1033
1035{
1036 vector<Graph::Node*> nodes;
1037 for (size_t i = 0; i < NUM_NODES; ++i)
1038 nodes.push_back(g.insert_node(static_cast<int>(i)));
1039
1040 std::mt19937 rng(42);
1041 std::uniform_int_distribution<size_t> dist(0, NUM_NODES - 1);
1042
1043 for (size_t i = 0; i < NUM_ARCS; ++i)
1044 {
1045 size_t src = dist(rng);
1046 size_t tgt = dist(rng);
1047 g.insert_arc(nodes[src], nodes[tgt], static_cast<double>(i));
1048 }
1049
1050 EXPECT_EQ(g.get_num_arcs(), NUM_ARCS);
1051}
1052
1054{
1055 vector<Graph::Node*> nodes;
1056 for (size_t i = 0; i < 100; ++i)
1057 nodes.push_back(g.insert_node(static_cast<int>(i)));
1058
1059 EXPECT_EQ(g.get_num_nodes(), 100);
1060
1061 // Remove half
1062 for (size_t i = 0; i < 50; ++i)
1063 g.remove_node(nodes[i]);
1064
1065 EXPECT_EQ(g.get_num_nodes(), 50);
1066}
1067
1068// =============================================================================
1069// Sorting Tests
1070// =============================================================================
1071
1073{
1074 g.sort_nodes([](Graph::Node *a, Graph::Node *b) {
1075 return a->get_info() > b->get_info();
1076 });
1077
1078 auto it = g.get_node_it();
1079 int prev = it.get_curr()->get_info();
1080 it.next();
1081
1082 while (it.has_curr())
1083 {
1084 EXPECT_GE(prev, it.get_curr()->get_info());
1085 prev = it.get_curr()->get_info();
1086 it.next();
1087 }
1088}
1089
1091{
1092 g.sort_arcs([](Graph::Arc *a, Graph::Arc *b) {
1093 return a->get_info() > b->get_info();
1094 });
1095
1096 auto it = g.get_arc_it();
1097 double prev = it.get_curr()->get_info();
1098 it.next();
1099
1100 while (it.has_curr())
1101 {
1102 EXPECT_GE(prev, it.get_curr()->get_info());
1103 prev = it.get_curr()->get_info();
1104 it.next();
1105 }
1106}
1107
1108// =============================================================================
1109// Clear Graph Tests
1110// =============================================================================
1111
1113{
1114 clear_graph(g);
1115 EXPECT_EQ(g.get_num_nodes(), 0);
1116 EXPECT_EQ(g.get_num_arcs(), 0);
1117}
1118
1119// =============================================================================
1120// C++20 Concepts Tests
1121// =============================================================================
1122
1123// Compile-time verification that iterators satisfy concepts
1125 "Node_Iterator must satisfy BasicGraphIterator");
1127 "Arc_Iterator must satisfy BasicGraphIterator");
1129 "Node_Iterator must satisfy GraphNodeIterator");
1131 "Arc_Iterator must satisfy GraphArcIterator");
1132
1133// Also verify for digraph
1135 "Digraph::Node_Iterator must satisfy BasicGraphIterator");
1137 "Digraph::Arc_Iterator must satisfy BasicGraphIterator");
1138
1140{
1141 Graph g;
1142 g.insert_node(1);
1143 g.insert_node(2);
1144
1145 auto it = g.get_node_it();
1146
1147 // Verify the interface works as expected by the concept
1148 EXPECT_TRUE(it.has_curr());
1149 EXPECT_NE(it.get_curr(), nullptr);
1150 it.next();
1151 EXPECT_TRUE(it.has_curr());
1152 it.next();
1153 EXPECT_FALSE(it.has_curr());
1154}
1155
1157{
1158 Graph g;
1159 auto n1 = g.insert_node(1);
1160 auto n2 = g.insert_node(2);
1161 g.insert_arc(n1, n2, 1.0);
1162
1163 auto it = g.get_arc_it();
1164
1165 EXPECT_TRUE(it.has_curr());
1166 EXPECT_NE(it.get_curr(), nullptr);
1167 it.next();
1168 EXPECT_FALSE(it.has_curr());
1169}
1170
1172{
1173 Graph g;
1174 auto n1 = g.insert_node(1);
1175 auto n2 = g.insert_node(2);
1176 g.insert_arc(n1, n2, 1.0);
1177
1178 auto it = g.get_arc_it(n1);
1179
1180 EXPECT_TRUE(it.has_curr());
1181 auto* arc = it.get_curr();
1182 EXPECT_NE(arc, nullptr);
1183
1184 // Node arc iterator should provide get_tgt_node
1185 auto* tgt = it.get_tgt_node();
1186 EXPECT_EQ(tgt, n2);
1187}
1188
1189// Test that concepts work with constrained template functions
1190template <BasicGraphIterator It>
1191size_t count_elements(It it)
1192{
1193 size_t count = 0;
1194 for (; it.has_curr(); it.next())
1195 ++count;
1196 return count;
1197}
1198
1200{
1201 Graph g;
1202 g.insert_node(1);
1203 g.insert_node(2);
1204 g.insert_node(3);
1205
1206 auto node_it = g.get_node_it();
1208}
1209
1210// =============================================================================
1211// Main
1212// =============================================================================
1213
1214int main(int argc, char **argv)
1215{
1217 return RUN_ALL_TESTS();
1218}
int main()
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
DynList & swap(DynList &l) noexcept
Swap this with l.
Definition htlist.H:1448
void next()
Advances the iterator to the next filtered element.
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
Node Node
The graph type.
Definition tpl_graph.H:432
Arc 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
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1206
Iterator on nodes and arcs of a path.
Definition tpl_graph.H:3201
bool has_current_node() const noexcept
Return true if the iterator has a current node.
Definition tpl_graph.H:3314
Path on a graph.
Definition tpl_graph.H:2669
bool is_cycle() const
Return true if this is a cycle; throws if path is empty.
Definition tpl_graph.H:3160
void insert(Arc *arc)
Insert an arc as the first of a path.
Definition tpl_graph.H:3008
DynList< Arc * > arcs() const
Return a list with the arcs of a path (order, according to the path)
Definition tpl_graph.H:3378
size_t size() const noexcept
Return the path length in nodes.
Definition tpl_graph.H:2807
bool contains_node(Node *node) const noexcept
Return true if node belongs to the path.
Definition tpl_graph.H:3349
void insert_directed(Node *p)
Append a node to a directed path.
Definition tpl_graph.H:3075
Node * get_first_node() const
Return the first node of path; throws overflow_error if path is empty.
Definition tpl_graph.H:3125
bool is_empty() const noexcept
Return true if the path is empty.
Definition tpl_graph.H:2813
bool contains_arc(Arc *arc) const noexcept
Return true if arc belongs to the path.
Definition tpl_graph.H:3358
Node * remove_first_node()
Remove the first node of a path.
Definition tpl_graph.H:3182
void append(Arc *arc)
Append an arc to the path.
Definition tpl_graph.H:2865
void append_directed(Node *p)
Append a node to a directed path.
Definition tpl_graph.H:2937
DynList< Node * > nodes() const
Return a list with the nodes of path (order according to the path)
Definition tpl_graph.H:3367
Node * get_last_node() const
Return the last node of path; throws overflow_error if path is empty.
Definition tpl_graph.H:3132
Node * remove_last_node()
Remove the last node of path.
Definition tpl_graph.H:3170
TestDigraph dg
vector< TestDigraph::Node * > nodes
vector< TestDigraph::Arc * > arcs
void SetUp() override
void SetUp() override
vector< TestDigraph::Node * > nodes
vector< TestDigraph::Arc * > arcs
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
void SetUp() override
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Definition graph-dry.H:2802
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2780
vector< Graph::Node * > nodes
void SetUp() override
vector< Graph::Node * > nodes
void SetUp() override
vector< Graph::Arc * > arcs
void SetUp() override
void SetUp() override
static constexpr size_t NUM_ARCS
static constexpr size_t NUM_NODES
vector< Graph::Arc * > arcs
vector< Graph::Node * > nodes
void SetUp() override
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
#define TEST(name)
static mt19937 rng
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
void clear_graph(GT &g) noexcept
Clean a graph: all its nodes and arcs are removed and freed.
Definition tpl_graph.H:3549
GT::Arc * search_arc(const GT &g, typename GT::Node *src, typename GT::Node *tgt, SA sa=SA()) noexcept
Arc filtered searching given two nodes.
Definition tpl_graph.H:2421
GT::Arc * search_directed_arc(const GT &g, typename GT::Node *src, typename GT::Node *tgt, SA sa=SA()) noexcept
Searching of directed arc linking two nodes.
Definition tpl_graph.H:2449
Path< GT > find_path_depth_first(const GT &g, typename GT::Node *start_node, typename GT::Node *end_node)
Depth-first search of a path between two nodes.
Definition tpl_graph.H:3468
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.
STL namespace.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1164
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Node belonging to a graph implemented with a double linked adjacency list.
Definition tpl_graph.H:121
bool operator()(Graph::Node *n) const noexcept
bool operator()(Graph::Arc *a) const noexcept
Generic graph and digraph implementations.
TEST_F(GraphBasicTest, DefaultConstructorCreatesEmptyGraph)
size_t count_elements(It it)