Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_graph_utils_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
48#include <gtest/gtest.h>
49
50#include <functional>
51#include <queue>
52#include <random>
53#include <set>
54#include <tuple>
55#include <vector>
56
57#include <tpl_dynArray.H>
58#include <tpl_graph.H>
59#include <tpl_graph_utils.H>
60
61using namespace Aleph;
62
63namespace
64{
68
69 std::vector<Graph::Node *> make_nodes(Graph &g, int n)
70 {
71 std::vector<Graph::Node *> nodes;
72 nodes.reserve(n);
73 for (int i = 0; i < n; ++i)
74 nodes.push_back(g.insert_node(i));
75 return nodes;
76 }
77
78 std::vector<TestDigraph::Node *> make_nodes(TestDigraph &g, int n)
79 {
80 std::vector<TestDigraph::Node *> nodes;
81 nodes.reserve(n);
82 for (int i = 0; i < n; ++i)
83 nodes.push_back(g.insert_node(i));
84 return nodes;
85 }
86
87 std::vector<WGraph::Node *> make_nodes(WGraph &g, int n)
88 {
89 std::vector<WGraph::Node *> nodes;
90 nodes.reserve(n);
91 for (int i = 0; i < n; ++i)
92 nodes.push_back(g.insert_node(i));
93 return nodes;
94 }
95
96 // ---------------------------------------------------------------------------
97 // Helpers for function-pointer traversals
98 // ---------------------------------------------------------------------------
99
100 Graph::Node *g_expected_start = nullptr;
101
103 {
104 if (node == g_expected_start)
105 EXPECT_EQ(from, nullptr);
106 else
107 EXPECT_NE(from, nullptr);
108 return false;
109 }
110
111 bool stop_immediately(const Graph &, Graph::Node *, Graph::Arc *)
112 {
113 return true;
114 }
115
116 // ---------------------------------------------------------------------------
117 // Operation & filter helpers for traversal functors
118 // ---------------------------------------------------------------------------
119
120 template <class GT>
121 struct CollectVisitedInfos
122 {
123 std::vector<int> *infos = nullptr;
124
125 bool operator()(const GT &, typename GT::Node *node, typename GT::Arc *)
126 {
127 infos->push_back(node->get_info());
128 return false;
129 }
130 };
131
132 template <class GT>
133 struct EvenArcInfoOnly
134 {
135 bool operator()(typename GT::Arc *a) const noexcept
136 {
137 return (a->get_info() % 2) == 0;
138 }
139 };
140
141 // ---------------------------------------------------------------------------
142 // Reference BFS on adjacency list (undirected) for property tests
143 // ---------------------------------------------------------------------------
144
145 int bfs_distance(const std::vector<std::vector<int>> &adj, int s, int t)
146 {
147 if (s == t)
148 return 0;
149
150 std::vector<int> dist(adj.size(), -1);
151 std::queue<int> q;
152 dist[s] = 0;
153 q.push(s);
154
155 while (!q.empty())
156 {
157 int u = q.front();
158 q.pop();
159 for (int v : adj[u])
160 {
161 if (dist[v] != -1)
162 continue;
163 dist[v] = dist[u] + 1;
164 if (v == t)
165 return dist[v];
166 q.push(v);
167 }
168 }
169
170 return -1;
171 }
172
173 template <class GT>
174 std::vector<typename GT::Node *> path_nodes(const Path<GT> &path)
175 {
176 std::vector<typename GT::Node *> nodes;
177 path.for_each_node([&](auto p) { nodes.push_back(p); });
178 return nodes;
179 }
180
181} // namespace
182
183// =============================================================================
184// Traversals (free functions)
185// =============================================================================
186
188{
189 Graph g;
190 auto nodes = make_nodes(g, 5);
191 g.insert_arc(nodes[0], nodes[1], 1);
192 g.insert_arc(nodes[1], nodes[2], 1);
193 g.insert_arc(nodes[2], nodes[3], 1);
194 g.insert_arc(nodes[3], nodes[4], 1);
195
196 const auto no_visit =
197 static_cast<bool (*)(const Graph &, Graph::Node *, Graph::Arc *)>(nullptr);
198 const size_t visited = depth_first_traversal(g, nodes[0], no_visit);
199 EXPECT_EQ(visited, 5U);
200
201 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
202 EXPECT_TRUE(IS_NODE_VISITED(it.get_curr(), Depth_First));
203}
204
206{
207 Graph g;
208 auto nodes = make_nodes(g, 3);
209 g.insert_arc(nodes[0], nodes[1], 1);
210 g.insert_arc(nodes[1], nodes[2], 1);
211
214}
215
217{
218 Graph g;
219 auto nodes = make_nodes(g, 3);
220 g.insert_arc(nodes[0], nodes[1], 1);
221 g.insert_arc(nodes[1], nodes[2], 1);
222
223 const size_t visited = depth_first_traversal(g, nodes[0], &stop_immediately);
224 EXPECT_EQ(visited, 1U);
225}
226
228{
229 Graph g;
230 auto nodes = make_nodes(g, 5);
231 g.insert_arc(nodes[0], nodes[1], 1);
232 g.insert_arc(nodes[1], nodes[2], 1);
233 g.insert_arc(nodes[2], nodes[3], 1);
234 g.insert_arc(nodes[3], nodes[4], 1);
235
236 const auto no_visit =
237 static_cast<bool (*)(const Graph &, Graph::Node *, Graph::Arc *)>(nullptr);
238 const size_t visited = breadth_first_traversal(g, nodes[0], no_visit);
239 EXPECT_EQ(visited, 5U);
240
241 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
243}
244
255
257{
258 Graph g;
259 auto nodes = make_nodes(g, 3);
260 g.insert_arc(nodes[0], nodes[1], 1);
261 g.insert_arc(nodes[1], nodes[2], 1);
262
264 EXPECT_EQ(visited, 1U);
265}
266
267// =============================================================================
268// Traversal functors (filters + operations)
269// =============================================================================
270
272{
273 Graph g;
274 auto nodes = make_nodes(g, 3);
275 g.insert_arc(nodes[0], nodes[1], 2); // allowed (even)
276 g.insert_arc(nodes[1], nodes[2], 1); // filtered out
277
278 std::vector<int> visited_infos;
280
283
284 const size_t visited = dft(g, nodes[0], op);
285 EXPECT_EQ(visited, 2U);
286
287 std::set<int> s(visited_infos.begin(), visited_infos.end());
288 EXPECT_EQ(s, (std::set<int>{0, 1}));
289}
290
292{
293 Graph g;
294 auto nodes = make_nodes(g, 3);
295 g.insert_arc(nodes[0], nodes[1], 2); // allowed (even)
296 g.insert_arc(nodes[1], nodes[2], 1); // filtered out
297
298 std::vector<int> visited_infos;
300
303
304 const size_t visited = bft(g, nodes[0], op);
305 EXPECT_EQ(visited, 2U);
306
307 std::set<int> s(visited_infos.begin(), visited_infos.end());
308 EXPECT_EQ(s, (std::set<int>{0, 1}));
309}
310
311// =============================================================================
312// Path search
313// =============================================================================
314
316{
317 Graph g;
318 auto nodes = make_nodes(g, 3);
319 g.insert_arc(nodes[0], nodes[1], 1);
320 g.insert_arc(nodes[1], nodes[2], 1);
321
322 auto path = find_path_breadth_first(g, nodes[1], nodes[1]);
323 EXPECT_FALSE(path.is_empty());
324 EXPECT_EQ(path.size(), 1U);
325 EXPECT_EQ(path.get_first_node(), nodes[1]);
326 EXPECT_EQ(path.get_last_node(), nodes[1]);
327}
328
330{
331 Graph g;
332 auto nodes = make_nodes(g, 4);
333 g.insert_arc(nodes[0], nodes[1], 1);
334 g.insert_arc(nodes[2], nodes[3], 1);
335
336 auto path = find_path_breadth_first(g, nodes[0], nodes[3]);
337 EXPECT_TRUE(path.is_empty());
338 EXPECT_TRUE(path.inside_graph(g));
339}
340
342{
343 Graph g;
344 auto nodes = make_nodes(g, 4);
345 g.insert_arc(nodes[0], nodes[3], 1); // direct
346 g.insert_arc(nodes[0], nodes[1], 1);
347 g.insert_arc(nodes[1], nodes[2], 1);
348 g.insert_arc(nodes[2], nodes[3], 1); // longer
349
350 auto path = find_path_breadth_first(g, nodes[0], nodes[3]);
351 ASSERT_FALSE(path.is_empty());
352 EXPECT_EQ(path.size(), 2U);
353
354 auto seq = path_nodes(path);
355 ASSERT_EQ(seq.size(), 2U);
356 EXPECT_EQ(seq.front(), nodes[0]);
357 EXPECT_EQ(seq.back(), nodes[3]);
358 EXPECT_NE(search_arc(g, seq[0], seq[1]), nullptr);
359}
360
362{
363 std::mt19937 rng(123456);
364 std::uniform_int_distribution<int> n_dist(2, 10);
365 std::bernoulli_distribution edge_dist(0.25);
366 std::uniform_int_distribution<int> pick_dist(0, 9);
367
368 for (int iter = 0; iter < 200; ++iter)
369 {
370 const int n = n_dist(rng);
371
372 Graph g;
373 auto nodes = make_nodes(g, n);
374 std::vector<std::vector<int>> adj(n);
375
376 for (int u = 0; u < n; ++u)
377 for (int v = u + 1; v < n; ++v)
378 if (edge_dist(rng))
379 {
380 g.insert_arc(nodes[u], nodes[v], 1);
381 adj[u].push_back(v);
382 adj[v].push_back(u);
383 }
384
385 const int s = pick_dist(rng) % n;
386 const int t = pick_dist(rng) % n;
387
388 const int ref = bfs_distance(adj, s, t);
389 auto path = find_path_breadth_first(g, nodes[s], nodes[t]);
390
391 if (ref < 0)
392 {
393 EXPECT_TRUE(path.is_empty());
394 }
395 else
396 {
397 ASSERT_FALSE(path.is_empty());
398 EXPECT_EQ(path.size(), static_cast<size_t>(ref + 1));
399
400 auto seq = path_nodes(path);
401 ASSERT_EQ(seq.front(), nodes[s]);
402 ASSERT_EQ(seq.back(), nodes[t]);
403 for (size_t i = 0; i + 1 < seq.size(); ++i)
404 EXPECT_NE(search_arc(g, seq[i], seq[i + 1]), nullptr);
405 }
406 }
407}
408
409// =============================================================================
410// Connectivity / cycles / reachability
411// =============================================================================
412
414{
415 Graph empty;
417
419 (void)single.insert_node(1);
421
422 Graph g;
423 auto nodes = make_nodes(g, 4);
424 g.insert_arc(nodes[0], nodes[1], 1);
425 g.insert_arc(nodes[1], nodes[2], 1);
426 EXPECT_FALSE(test_connectivity(g)); // node[3] disconnected
427
428 g.insert_arc(nodes[2], nodes[3], 1);
430}
431
433{
434 TestDigraph dg;
435 auto nodes = make_nodes(dg, 2);
436 dg.insert_arc(nodes[0], nodes[1], 1);
437 EXPECT_THROW(test_connectivity(dg), std::domain_error);
438}
439
441{
442 Graph g;
443 auto nodes = make_nodes(g, 3);
444 g.insert_arc(nodes[0], nodes[1], 1);
445 g.insert_arc(nodes[1], nodes[2], 1);
447
448 g.insert_arc(nodes[2], nodes[0], 1); // triangle
450
451 EXPECT_THROW(test_for_cycle(g, nullptr), std::invalid_argument);
452}
453
455{
456 Graph empty;
458 EXPECT_FALSE(has_cycle(empty));
459
460 Graph tree;
461 auto nodes = make_nodes(tree, 4);
462 tree.insert_arc(nodes[0], nodes[1], 1);
463 tree.insert_arc(nodes[1], nodes[2], 1);
464 tree.insert_arc(nodes[2], nodes[3], 1);
466 EXPECT_FALSE(has_cycle(tree));
467
468 tree.insert_arc(nodes[3], nodes[0], 1);
470 EXPECT_TRUE(has_cycle(tree));
471}
472
474{
475 TestDigraph dg;
476 auto nodes = make_nodes(dg, 2);
477 dg.insert_arc(nodes[0], nodes[1], 1);
478 EXPECT_THROW(is_graph_acyclique(dg), std::domain_error);
479 EXPECT_THROW(is_graph_acyclique(dg, nodes[0]), std::domain_error);
480 EXPECT_THROW(is_graph_acyclique(dg, nullptr), std::domain_error);
481}
482
484{
485 Graph g;
486 auto nodes = make_nodes(g, 6);
487
488 // Two disjoint triangles (E == V) => there is no path across components.
489 g.insert_arc(nodes[0], nodes[1], 1);
490 g.insert_arc(nodes[1], nodes[2], 1);
491 g.insert_arc(nodes[2], nodes[0], 1);
492
493 g.insert_arc(nodes[3], nodes[4], 1);
494 g.insert_arc(nodes[4], nodes[5], 1);
495 g.insert_arc(nodes[5], nodes[3], 1);
496
499
500 EXPECT_THROW(test_for_path(g, nullptr, nodes[0]), std::invalid_argument);
501 EXPECT_THROW(test_for_path(g, nodes[0], nullptr), std::invalid_argument);
502}
503
504// =============================================================================
505// Connected components and subgraph mapping
506// =============================================================================
507
509{
510 Graph g;
511 auto nodes = make_nodes(g, 4);
512 auto a01 = g.insert_arc(nodes[0], nodes[1], 1);
513 auto a12 = g.insert_arc(nodes[1], nodes[2], 1);
514
516
517 std::multiset<std::pair<size_t, size_t>> sizes;
518 size_t comp_count = 0;
519 for (auto it = comps.get_it(); it.has_curr(); it.next_ne())
520 {
521 ++comp_count;
522 auto &sg = it.get_curr();
523 sizes.insert({sg.get_num_nodes(), sg.get_num_arcs()});
524 }
525
527 EXPECT_EQ(sizes, (std::multiset<std::pair<size_t, size_t>>{{3U, 2U}, {1U, 0U}}));
528
529 // Nodes and arcs must be mapped both ways through cookies.
530 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
531 {
532 auto gp = it.get_curr();
533 auto sp = mapped_node<Graph>(gp);
534 ASSERT_NE(sp, nullptr);
535 EXPECT_EQ(sp->get_info(), gp->get_info());
537 }
538
543}
544
546{
547 Graph g;
548 auto nodes = make_nodes(g, 4);
549 g.insert_arc(nodes[0], nodes[1], 1);
550 g.insert_arc(nodes[1], nodes[2], 1);
551 // node[3] is isolated
552
553 g.reset_nodes();
554 g.reset_arcs();
555
556 Graph sg;
557 size_t visited = 0;
558 build_subgraph(g, sg, nodes[0], visited);
559
560 EXPECT_EQ(visited, 3U);
561 EXPECT_EQ(sg.get_num_nodes(), 3U);
562 EXPECT_EQ(sg.get_num_arcs(), 2U);
563}
564
565// =============================================================================
566// Spanning trees
567// =============================================================================
568
570{
571 Graph g;
572 auto nodes = make_nodes(g, 5);
573 g.insert_arc(nodes[0], nodes[1], 1);
574 g.insert_arc(nodes[1], nodes[2], 2);
575 g.insert_arc(nodes[2], nodes[3], 3);
576 g.insert_arc(nodes[3], nodes[4], 4);
577 g.insert_arc(nodes[0], nodes[4], 5); // add a cycle in the original graph
578
579 auto tree = find_depth_first_spanning_tree(g, nodes[0]);
580 EXPECT_EQ(tree.get_num_nodes(), g.get_num_nodes());
581 EXPECT_EQ(tree.get_num_arcs(), g.get_num_nodes() - 1);
583
584 auto img = mapped_node<Graph>(nodes[0]);
585 ASSERT_NE(img, nullptr);
587}
588
590{
591 Graph g;
592 auto nodes = make_nodes(g, 5);
593 g.insert_arc(nodes[0], nodes[1], 1);
594 g.insert_arc(nodes[1], nodes[2], 1);
595 g.insert_arc(nodes[2], nodes[3], 1);
596 g.insert_arc(nodes[3], nodes[4], 1);
597
598 g.reset_nodes();
599 g.reset_arcs();
600
601 auto tree = find_breadth_first_spanning_tree(g, nodes[0]);
602 EXPECT_EQ(tree.get_num_nodes(), g.get_num_nodes());
603 EXPECT_EQ(tree.get_num_arcs(), g.get_num_nodes() - 1);
605}
606
607// =============================================================================
608// Build spanning tree from arcs (DynArray)
609// =============================================================================
610
612{
613 Graph g;
614 auto nodes = make_nodes(g, 4);
615 auto a01 = g.insert_arc(nodes[0], nodes[1], 1);
616 auto a12 = g.insert_arc(nodes[1], nodes[2], 2);
617 auto a23 = g.insert_arc(nodes[2], nodes[3], 3);
618 (void)g.insert_arc(nodes[0], nodes[3], 99);
619
620 g.reset_nodes();
621 g.reset_arcs();
622
624 arcs.append(a01);
625 arcs.append(nullptr); // should be ignored
626 arcs.append(a12);
627 arcs.append(a23);
628
629 auto tree = build_spanning_tree<Graph>(arcs);
630 EXPECT_EQ(tree.get_num_nodes(), 4U);
631 EXPECT_EQ(tree.get_num_arcs(), 3U);
632
633 // Mapping is ret -> original via cookies.
634 for (auto it = tree.get_node_it(); it.has_curr(); it.next_ne())
635 {
636 auto tp = it.get_curr();
637 auto gp = static_cast<Graph::Node *>(NODE_COOKIE(tp));
638 ASSERT_NE(gp, nullptr);
639 EXPECT_EQ(gp->get_info(), tp->get_info());
640 }
641
642 for (auto it = tree.get_arc_it(); it.has_curr(); it.next_ne())
643 {
644 auto ta = it.get_curr();
645 auto ga = static_cast<Graph::Arc *>(ARC_COOKIE(ta));
646 ASSERT_NE(ga, nullptr);
647 EXPECT_EQ(ta->get_info(), ga->get_info());
648 }
649
650 // Original graph cookies must remain untouched.
651 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
652 EXPECT_EQ(NODE_COOKIE(it.get_curr()), nullptr);
653}
654
655// =============================================================================
656// Cut nodes / painting / cut graph extraction
657// =============================================================================
658
660{
661 Graph g;
662 auto nodes = make_nodes(g, 4);
663 g.insert_arc(nodes[0], nodes[1], 1);
664 g.insert_arc(nodes[1], nodes[2], 1);
665 g.insert_arc(nodes[2], nodes[3], 1);
666
667 auto cut_nodes = compute_cut_nodes(g, nodes[0]);
668
669 std::set<int> infos;
670 for (auto it = cut_nodes.get_it(); it.has_curr(); it.next_ne())
671 infos.insert(it.get_curr()->get_info());
672
673 EXPECT_EQ(infos, (std::set<int>{1, 2}));
674
675 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
676 EXPECT_EQ(NODE_COOKIE(it.get_curr()), nullptr);
677
678 // Digraphs are rejected.
679 TestDigraph dg;
680 auto dn = make_nodes(dg, 2);
681 dg.insert_arc(dn[0], dn[1], 1);
682 EXPECT_THROW(compute_cut_nodes(dg, dn[0]), std::domain_error);
683}
684
686{
687 Graph g;
688 auto nodes = make_nodes(g, 4);
689 auto a01 = g.insert_arc(nodes[0], nodes[1], 1);
690 auto a12 = g.insert_arc(nodes[1], nodes[2], 1);
691 auto a23 = g.insert_arc(nodes[2], nodes[3], 1);
692
693 auto cut_nodes = compute_cut_nodes(g, nodes[0]);
694 const long colors_end = paint_subgraphs(g, cut_nodes);
696
697 auto [cut_graph, cross_arcs] = map_cut_graph(g, cut_nodes);
698 EXPECT_EQ(cut_graph.get_num_nodes(), 2U);
699 EXPECT_EQ(cut_graph.get_num_arcs(), 1U);
700
701 // Cross arcs are the two edges adjacent to the cut nodes but reaching non-cut nodes.
702 std::set<Graph::Arc *> cross_set;
703 for (auto it = cross_arcs.get_it(); it.has_curr(); it.next_ne())
704 cross_set.insert(it.get_curr());
705
706 EXPECT_EQ(cross_set, (std::set<Graph::Arc *>{a01, a23}));
707
708 (void)a12; // cut arc is between the two cut nodes
709}
710
712{
713 Graph g;
714 auto nodes = make_nodes(g, 6); // 0 center, 1..5 leaves
715
716 for (int i = 1; i < 6; ++i)
717 g.insert_arc(nodes[0], nodes[i], 1);
718
719 auto cut_nodes = compute_cut_nodes(g, nodes[0]);
720 const long colors_end = paint_subgraphs(g, cut_nodes);
721
722 // Each leaf is a separate block => 5 colors: [1..5], so colors_end == 6.
724
725 // Extract each painted block: each should be a single-node graph.
726 for (long c = 1; c < colors_end; ++c)
727 {
728 auto sg = map_subgraph(g, c);
729 EXPECT_EQ(sg.get_num_nodes(), 1U);
730 EXPECT_EQ(sg.get_num_arcs(), 0U);
731 }
732
733 auto [cut_graph, cross_arcs] = map_cut_graph(g, cut_nodes);
734 EXPECT_EQ(cut_graph.get_num_nodes(), 1U);
735 EXPECT_EQ(cut_graph.get_num_arcs(), 0U);
736
737 size_t cross_count = 0;
738 for (auto it = cross_arcs.get_it(); it.has_curr(); it.next_ne())
739 ++cross_count;
741}
742
743// =============================================================================
744// Digraph inversion (transpose)
745// =============================================================================
746
748{
749 TestDigraph g;
750 auto nodes = make_nodes(g, 3);
751 auto a01 = g.insert_arc(nodes[0], nodes[1], 42);
752 // nodes[2] is isolated
753
754 auto gi = invert_digraph(g);
755 EXPECT_EQ(gi.get_num_nodes(), 3U);
756 EXPECT_EQ(gi.get_num_arcs(), 1U);
757
761 ASSERT_NE(n0i, nullptr);
762 ASSERT_NE(n1i, nullptr);
763 ASSERT_NE(n2i, nullptr);
764
765 auto inv = search_directed_arc(gi, n1i, n0i);
766 ASSERT_NE(inv, nullptr);
767 EXPECT_EQ(inv->get_info(), 42);
768
771}
772
779
781{
782 struct OnlyTwo
783 {
784 bool operator()(TestDigraph::Arc *a) const noexcept { return a->get_info() == 2; }
785 void set_cookie(void *) noexcept {}
786 };
787
788 TestDigraph g;
789 auto nodes = make_nodes(g, 3);
790 auto a01 = g.insert_arc(nodes[0], nodes[1], 1);
791 auto a12 = g.insert_arc(nodes[1], nodes[2], 2);
792
794 auto gi = inv(g);
795
796 EXPECT_EQ(gi.get_num_nodes(), 3U);
797 EXPECT_EQ(gi.get_num_arcs(), 1U);
798
801 ASSERT_NE(n1i, nullptr);
802 ASSERT_NE(n2i, nullptr);
803
805 EXPECT_EQ(ARC_COOKIE(a01), nullptr);
806 EXPECT_NE(ARC_COOKIE(a12), nullptr);
807}
808
809// =============================================================================
810// Dft_Dist / get_min_path / Total_Cost
811// =============================================================================
812
818
820{
821 WGraph g;
822 auto nodes = make_nodes(g, 3);
823 g.insert_arc(nodes[0], nodes[1], 2.5);
824 g.insert_arc(nodes[1], nodes[2], 3.0);
825
826 g.reset_nodes();
827
828 NODE_COOKIE(nodes[1]) = nodes[0];
829 NODE_COOKIE(nodes[2]) = nodes[1];
830
831 Path<WGraph> path(g);
832 const double dist = get_min_path<WGraph>(nodes[0], nodes[2], path);
833 EXPECT_DOUBLE_EQ(dist, 5.5);
834 EXPECT_EQ(path.size(), 3U);
835
836 auto seq = path_nodes(path);
837 ASSERT_EQ(seq.size(), 3U);
838 EXPECT_EQ(seq.front(), nodes[0]);
839 EXPECT_EQ(seq.back(), nodes[2]);
840
841 // start == end is a valid trivial path.
842 const double dist0 = get_min_path<WGraph>(nodes[1], nodes[1], path);
844 EXPECT_EQ(path.size(), 1U);
845
846 // Broken chain (nullptr) must throw.
847 g.reset_nodes();
848 NODE_COOKIE(nodes[2]) = nullptr;
849 EXPECT_THROW(get_min_path<WGraph>(nodes[0], nodes[2], path), std::domain_error);
850}
851
853{
854 Graph g;
855 auto nodes = make_nodes(g, 4);
856 g.insert_arc(nodes[0], nodes[1], 1);
857 g.insert_arc(nodes[0], nodes[2], 2);
858 g.insert_arc(nodes[0], nodes[3], 3);
859
861 EXPECT_EQ(cost.total_cost(g), 6);
862
863 // Accumulator usage with traverse_arcs(): sum incident arcs to node[0].
864 cost.reset();
866 EXPECT_EQ(cost.value(), 6);
867}
Stateful breadth-first traversal functor.
Stateful depth-first traversal functor.
Default distance accessor for arc weights.
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
typename BaseGraph::Arc Arc
Definition graph-dry.H:3852
T & append()
Allocate a new entry to the end of array.
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Functor for computing the transposed digraph, filtering arcs.
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
Path on a graph.
Definition tpl_graph.H:2669
void for_each_node(Operation op=Operation()) const
Execute an operation on each node of path.
Definition tpl_graph.H:3331
size_t size() const noexcept
Return the path length in nodes.
Definition tpl_graph.H:2807
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 inside_graph(const GT &gr) const noexcept
Return true if this is on graph gr
Definition tpl_graph.H:2747
Node * get_last_node() const
Return the last node of path; throws overflow_error if path is empty.
Definition tpl_graph.H:3132
Compute the total cost (sum of arc weights) of a graph.
Distance::Distance_Type total_cost(GT &g)
Compute the total cost.
Distance::Distance_Type value() const noexcept
Return the accumulated value (after using operator()(Arc*)).
void reset() noexcept
Reset the internal accumulator used by operator()(Arc*).
NodeInfo & get_info() noexcept
Return a modifiable reference to the data contained in the node.
Definition graph-dry.H:494
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
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2780
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
#define TEST(name)
static mt19937 rng
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
size_t depth_first_traversal(const GT &g, typename GT::Node *start_node, bool(*visit)(const GT &g, typename GT::Node *, typename GT::Arc *))
Depth-first traversal starting from a given node.
#define ARC_COOKIE(p)
Return the arc cookie
bool has_cycle(const GT &g)
Return true if an undirected graph has at least one cycle.
DynList< GT > inconnected_components(const GT &g)
Forward declaration for inconnected_components().
bool test_for_cycle(const GT &g, typename GT::Node *src)
Search for a cycle reachable from a given node.
GT find_breadth_first_spanning_tree(GT &g, typename GT::Node *gp)
Build a breadth-first spanning tree (mapped to the original graph).
bool traverse_arcs(typename GT::Node *p, Operation op=Operation())
Generic arcs traverse of a node.
Definition tpl_graph.H:2027
#define IS_NODE_VISITED(p, bit)
Determine whether the control bit is set or not to one.
GT invert_digraph(const GT &g)
Compute the transpose (arc-reversed) digraph.
DynList< typename GT::Node * > compute_cut_nodes(const GT &g, typename GT::Node *start)
Compute articulation points (cut vertices) of an undirected graph.
bool test_connectivity(const GT &g)
Connectivity test for undirected graphs.
#define NODE_COOKIE(p)
Return the node cookie
long paint_subgraphs(const GT &g, const DynList< typename GT::Node * > &cut_node_list)
Paint connected blocks around articulation points.
Path< GT > find_path_breadth_first(const GT &g, typename GT::Node *start, typename GT::Node *end)
Breadth-first search of a (shortest-by-edges) path between two nodes.
bool test_for_path(const GT &g, typename GT::Node *start_node, typename GT::Node *end_node)
Return true if there is a path between two nodes.
size_t breadth_first_traversal(const GT &g, typename GT::Node *start, bool(*visit)(const GT &, typename GT::Node *, typename GT::Arc *))
Breadth-first traversal starting from a given node.
void build_subgraph(const GT &g, GT &sg, typename GT::Node *g_src, size_t &node_count)
Forward declaration for build_subgraph().
GT find_depth_first_spanning_tree(const GT &g, typename GT::Node *gnode)
Build a depth-first spanning tree (mapped to the original graph).
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
bool is_graph_acyclique(const GT &g, typename GT::Node *start_node)
Return true if an undirected graph is acyclic.
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
std::tuple< GT, DynList< typename GT::Arc * > > map_cut_graph(const GT &g, const DynList< typename GT::Node * > &cut_node_list)
Extract the cut graph and cross-arc list.
GT map_subgraph(const GT &g, const long color)
Extract a mapped subgraph containing a given color.
@ Depth_First
Definition aleph-graph.H:73
@ Breadth_First
Definition aleph-graph.H:74
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
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1119
Lazy and scalable dynamic array implementation.
Generic graph and digraph implementations.
Utility algorithms and operations for graphs.