Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
latex_floyd_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
44#include <gtest/gtest.h>
45#include <sstream>
46#include <fstream>
47#include <limits>
48#include <cmath>
49
50#include <tpl_graph.H>
51#include <tpl_matgraph.H>
52#include <latex_floyd.H>
53
54using namespace std;
55using namespace testing;
56using namespace Aleph;
57
58// ============================================================================
59// Arc type with distance for Floyd-Warshall
60// ============================================================================
61
64{
66
67 static constexpr Distance_Type Max_Distance = numeric_limits<double>::infinity();
68 static constexpr Distance_Type Zero_Distance = 0.0;
69
71
74
76
77 operator Distance_Type() const { return distance; }
78};
79
82{
84
85 static constexpr Distance_Type Max_Distance = numeric_limits<int>::max() / 2; // Avoid overflow
86 static constexpr Distance_Type Zero_Distance = 0;
87
89
92
94
95 operator Distance_Type() const { return distance; }
96};
97
98// ============================================================================
99// Test Fixtures
100// ============================================================================
101
103class FloydSimpleGraphTest : public Test
104{
105protected:
110
116
117 void SetUp() override
118 {
119 // Create a simple graph:
120 // 1
121 // 0 -----> 1
122 // | |
123 // |4 |2
124 // v v
125 // 3 <----- 2
126 // 1
127 //
128 // Also: direct edge 0->2 with weight 5 (longer than 0->1->2 = 3)
129
130 n0 = g.insert_node(0);
131 n1 = g.insert_node(1);
132 n2 = g.insert_node(2);
133 n3 = g.insert_node(3);
134
135 g.insert_arc(n0, n1, DistanceArc(1.0)); // 0 -> 1: weight 1
136 g.insert_arc(n1, n2, DistanceArc(2.0)); // 1 -> 2: weight 2
137 g.insert_arc(n2, n3, DistanceArc(1.0)); // 2 -> 3: weight 1
138 g.insert_arc(n0, n3, DistanceArc(4.0)); // 0 -> 3: weight 4 (longer than 0->1->2->3 = 4)
139 g.insert_arc(n0, n2, DistanceArc(5.0)); // 0 -> 2: weight 5 (longer than 0->1->2 = 3)
140 }
141
142 // Helper to get node index by node pointer using matrix iteration
143 long get_index(Ady_Mat<Graph, Dist>& mat, Node* node) const
144 {
145 long n = mat.get_num_nodes();
146 for (long i = 0; i < n; ++i)
147 if (mat(i) == node)
148 return i;
149 return -1;
150 }
151};
152
154class FloydIntGraphTest : public Test
155{
156protected:
161
163 vector<Node*> nodes;
164
165 void SetUp() override
166 {
167 // Create a 4-node graph with known shortest paths
168 for (int i = 0; i < 4; ++i)
169 nodes.push_back(g.insert_node(i));
170
171 // Edges: forms a square with diagonal
172 // 0 --2-- 1
173 // | / |
174 // 3 1 4
175 // | / |
176 // 2 --5-- 3
177
178 g.insert_arc(nodes[0], nodes[1], IntDistanceArc(2));
179 g.insert_arc(nodes[1], nodes[0], IntDistanceArc(2));
180 g.insert_arc(nodes[0], nodes[2], IntDistanceArc(3));
181 g.insert_arc(nodes[2], nodes[0], IntDistanceArc(3));
182 g.insert_arc(nodes[1], nodes[2], IntDistanceArc(1)); // Diagonal shortcut
183 g.insert_arc(nodes[2], nodes[1], IntDistanceArc(1));
184 g.insert_arc(nodes[1], nodes[3], IntDistanceArc(4));
185 g.insert_arc(nodes[3], nodes[1], IntDistanceArc(4));
186 g.insert_arc(nodes[2], nodes[3], IntDistanceArc(5));
187 g.insert_arc(nodes[3], nodes[2], IntDistanceArc(5));
188 }
189};
190
191// ============================================================================
192// floyd_all_shortest_paths() Tests
193// ============================================================================
194
196{
197 Ady_Mat<Graph, Dist> dist(g);
198 Ady_Mat<Graph, long> path(g);
199
200 floyd_all_shortest_paths(g, dist, path);
201
202 // Diagonal should be zero
203 const long n = g.get_num_nodes();
204 for (long i = 0; i < n; ++i)
205 EXPECT_DOUBLE_EQ(dist(i, i), 0.0) << "Diagonal at " << i << " should be 0";
206}
207
209{
210 Ady_Mat<Graph, Dist> dist(g);
211 Ady_Mat<Graph, long> path(g);
212
213 floyd_all_shortest_paths(g, dist, path);
214
215 // Get indices for n0 and n1
216 long idx0 = get_index(dist, n0);
217 long idx1 = get_index(dist, n1);
218
219 // Direct edge 0->1 has weight 1
220 EXPECT_DOUBLE_EQ(dist(idx0, idx1), 1.0);
221}
222
224{
225 Ady_Mat<Graph, Dist> dist(g);
226 Ady_Mat<Graph, long> path(g);
227
228 floyd_all_shortest_paths(g, dist, path);
229
230 long idx0 = get_index(dist, n0);
231 long idx2 = get_index(dist, n2);
232
233 // 0->2: direct is 5, but 0->1->2 = 1+2 = 3
234 EXPECT_DOUBLE_EQ(dist(idx0, idx2), 3.0);
235}
236
238{
239 Ady_Mat<Graph, Dist> dist(g);
240 Ady_Mat<Graph, long> path(g);
241
242 floyd_all_shortest_paths(g, dist, path);
243
244 long idx0 = get_index(dist, n0);
245 long idx3 = get_index(dist, n3);
246
247 // 0->3: direct is 4, path 0->1->2->3 = 1+2+1 = 4 (same)
248 EXPECT_DOUBLE_EQ(dist(idx0, idx3), 4.0);
249}
250
252{
253 Ady_Mat<Graph, Dist> dist(g);
254 Ady_Mat<Graph, long> path(g);
255
256 floyd_all_shortest_paths(g, dist, path);
257
258 long idx1 = get_index(dist, n1);
259 long idx0 = get_index(dist, n0);
260
261 // Node 0 is not reachable from node 1 (directed graph)
262 EXPECT_TRUE(isinf(dist(idx1, idx0)));
263}
264
266{
267 Ady_Mat<Graph, Dist> dist(g);
268 Ady_Mat<Graph, long> path(g);
269
270 floyd_all_shortest_paths(g, dist, path);
271
272 const long n = g.get_num_nodes();
273
274 // For this undirected-like graph, dist(i,j) == dist(j,i)
275 for (long i = 0; i < n; ++i)
276 for (long j = 0; j < n; ++j)
277 EXPECT_EQ(dist(i, j), dist(j, i))
278 << "Distance should be symmetric for i=" << i << ", j=" << j;
279}
280
282{
283 Ady_Mat<Graph, Dist> dist(g);
284 Ady_Mat<Graph, long> path(g);
285
286 floyd_all_shortest_paths(g, dist, path);
287
288 // Find indices - nodes[0] should be at some index
289 long idx0 = -1, idx3 = -1;
290 const long n = g.get_num_nodes();
291 for (long i = 0; i < n; ++i) {
292 if (dist(i)->get_info() == 0) idx0 = i;
293 if (dist(i)->get_info() == 3) idx3 = i;
294 }
295
296 // 0->3: best path is 0->1->3 = 2+4 = 6
297 EXPECT_EQ(dist(idx0, idx3), 6);
298}
299
300// ============================================================================
301// find_min_path() Tests
302// ============================================================================
303
305{
306 Ady_Mat<Graph, Dist> dist(g);
307 Ady_Mat<Graph, long> path(g);
308
309 floyd_all_shortest_paths(g, dist, path);
310
311 Path<Graph> p(g);
312 long idx0 = get_index(dist, n0);
313
314 find_min_path(path, idx0, idx0, p);
315
316 // Path from node to itself should just contain the source
317 EXPECT_EQ(p.size(), 1u);
318}
319
321{
322 Ady_Mat<Graph, Dist> dist(g);
323 Ady_Mat<Graph, long> path(g);
324
325 floyd_all_shortest_paths(g, dist, path);
326
327 Path<Graph> p(g);
328 long idx0 = get_index(dist, n0);
329 long idx1 = get_index(dist, n1);
330
331 find_min_path(path, idx0, idx1, p);
332
333 // Path 0->1 should have 2 nodes
334 EXPECT_EQ(p.size(), 2u);
335}
336
338{
339 Ady_Mat<Graph, Dist> dist(g);
340 Ady_Mat<Graph, long> path(g);
341
342 floyd_all_shortest_paths(g, dist, path);
343
344 Path<Graph> p(g);
345 long idx0 = get_index(dist, n0);
346 long idx2 = get_index(dist, n2);
347
348 find_min_path(path, idx0, idx2, p);
349
350 // Shortest path 0->2 goes through 1, so path is 0->1->2 (3 nodes)
351 EXPECT_EQ(p.size(), 3u);
352}
353
354// ============================================================================
355// floyd_all_shortest_paths_latex() Tests
356// ============================================================================
357
358// Formatters for LaTeX output - must match mat_latex.H signatures
359
361template <class Mat>
363{
364 string operator()(Mat& mat, int i) const
365 {
366 return to_string(mat(static_cast<long>(i))->get_info());
367 }
368};
369
371template <class Mat>
373{
374 string operator()(Mat& mat, int i, int j) const
375 {
376 long val = mat(static_cast<long>(i), static_cast<long>(j));
377 return to_string(val);
378 }
379};
380
382template <class Mat>
384{
385 string operator()(Mat& mat, int i, int j) const
386 {
387 auto val = mat(static_cast<long>(i), static_cast<long>(j));
388 if (isinf(static_cast<double>(val)))
389 return "\\infty";
390 return to_string(static_cast<int>(val));
391 }
392};
393
395{
396 Ady_Mat<Graph, Dist> dist(g);
397 Ady_Mat<Graph, long> path(g);
398
399 // Create temp file
400 string filename = "/tmp/floyd_test_latex.tex";
401 ofstream output(filename);
402
405 (g, dist, path, output);
406
407 output.close();
408
409 // Read back and check
410 ifstream input(filename);
411 stringstream ss;
412 ss << input.rdbuf();
413 string content = ss.str();
414
415 EXPECT_NE(content.find("\\begin{figure}"), string::npos);
416 EXPECT_NE(content.find("\\end{figure}"), string::npos);
417}
418
420{
421 Ady_Mat<Graph, Dist> dist(g);
422 Ady_Mat<Graph, long> path(g);
423
424 string filename = "/tmp/floyd_test_latex2.tex";
425 ofstream output(filename);
426
429 (g, dist, path, output);
430
431 output.close();
432
433 ifstream input(filename);
434 stringstream ss;
435 ss << input.rdbuf();
436 string content = ss.str();
437
438 // Should contain D_0, P_0, D_1, P_1, etc.
439 EXPECT_NE(content.find("D_0"), string::npos);
440 EXPECT_NE(content.find("P_0"), string::npos);
441 EXPECT_NE(content.find("D_1"), string::npos);
442 EXPECT_NE(content.find("P_1"), string::npos);
443}
444
446{
447 Ady_Mat<Graph, Dist> dist(g);
448 Ady_Mat<Graph, long> path(g);
449
450 string filename = "/tmp/floyd_test_latex3.tex";
451 ofstream output(filename);
452
455 (g, dist, path, output);
456
457 output.close();
458
459 ifstream input(filename);
460 stringstream ss;
461 ss << input.rdbuf();
462 string content = ss.str();
463
464 // For n=4 nodes, we should have D_0 through D_4 (5 matrices)
465 // Actually D_0 initial, then D_1 through D_n
466 const long n = g.get_num_nodes();
467 for (long i = 0; i <= n; ++i) {
468 string dmat = "D_" + to_string(i);
469 EXPECT_NE(content.find(dmat), string::npos) << "Missing " << dmat;
470 }
471}
472
473// ============================================================================
474// Edge Cases
475// ============================================================================
476
478{
480
481 Graph g;
482 g.insert_node(0);
483
484 Ady_Mat<Graph, int> dist(g);
485 Ady_Mat<Graph, long> path(g);
486
487 floyd_all_shortest_paths(g, dist, path);
488
489 // Single node: distance to itself is 0
490 EXPECT_EQ(dist(0L, 0L), 0);
491}
492
494{
496
497 Graph g;
498 auto* n0 = g.insert_node(0);
499 auto* n1 = g.insert_node(1);
500 g.insert_arc(n0, n1, IntDistanceArc(5));
501
502 Ady_Mat<Graph, int> dist(g);
503 Ady_Mat<Graph, long> path(g);
504
505 floyd_all_shortest_paths(g, dist, path);
506
507 // Find indices for nodes
508 long idx0 = -1, idx1 = -1;
509 for (long i = 0; i < 2; ++i) {
510 if (dist(i)->get_info() == 0) idx0 = i;
511 if (dist(i)->get_info() == 1) idx1 = i;
512 }
513
514 EXPECT_EQ(dist(idx0, idx0), 0);
515 EXPECT_EQ(dist(idx1, idx1), 0);
516 EXPECT_EQ(dist(idx0, idx1), 5);
517 EXPECT_EQ(dist(idx1, idx0), IntDistanceArc::Max_Distance); // Not reachable
518}
519
521{
523
524 Graph g;
525 auto* n0 = g.insert_node(0);
526 auto* n1 = g.insert_node(1);
527 auto* n2 = g.insert_node(2);
528 auto* n3 = g.insert_node(3);
529
530 // Two disconnected components: {0,1} and {2,3}
531 g.insert_arc(n0, n1, IntDistanceArc(1));
532 g.insert_arc(n1, n0, IntDistanceArc(1));
533 g.insert_arc(n2, n3, IntDistanceArc(2));
534 g.insert_arc(n3, n2, IntDistanceArc(2));
535
536 Ady_Mat<Graph, int> dist(g);
537 Ady_Mat<Graph, long> path(g);
538
539 floyd_all_shortest_paths(g, dist, path);
540
541 // Map node info -> matrix index (Ady_Mat sorts nodes by pointer value)
542 vector<long> idx(4, -1);
543 for (long i = 0; i < 4; ++i)
544 idx[dist(i)->get_info()] = i;
545
546 // Within component 1
547 EXPECT_EQ(dist(idx[0], idx[1]), 1);
548 EXPECT_EQ(dist(idx[1], idx[0]), 1);
549
550 // Within component 2
551 EXPECT_EQ(dist(idx[2], idx[3]), 2);
552 EXPECT_EQ(dist(idx[3], idx[2]), 2);
553
554 // Between components (unreachable)
555 EXPECT_EQ(dist(idx[0], idx[2]), IntDistanceArc::Max_Distance);
556 EXPECT_EQ(dist(idx[1], idx[3]), IntDistanceArc::Max_Distance);
557}
558
560{
562
563 Graph g;
564 auto* n0 = g.insert_node(0);
565 auto* n1 = g.insert_node(1);
566 auto* n2 = g.insert_node(2);
567 auto* n3 = g.insert_node(3);
568
569 // Component 1: negative edge but no negative cycle
570 g.insert_arc(n0, n1, IntDistanceArc(-5));
571 g.insert_arc(n1, n0, IntDistanceArc(6));
572
573 // Component 2: separate disconnected component
574 g.insert_arc(n2, n3, IntDistanceArc(2));
575 g.insert_arc(n3, n2, IntDistanceArc(2));
576
577 Ady_Mat<Graph, int> dist(g);
578 Ady_Mat<Graph, long> path(g);
579
580 floyd_all_shortest_paths(g, dist, path);
581
582 // Map node info -> matrix index
583 vector<long> idx(4, -1);
584 for (long i = 0; i < 4; ++i)
585 idx[dist(i)->get_info()] = i;
586
587 // Within component 1
588 EXPECT_EQ(dist(idx[0], idx[1]), -5);
589 EXPECT_EQ(dist(idx[1], idx[0]), 6);
590
591 // Between components (unreachable) must remain infinity sentinel even with negative weights
592 EXPECT_EQ(dist(idx[0], idx[2]), IntDistanceArc::Max_Distance);
593 EXPECT_EQ(dist(idx[1], idx[3]), IntDistanceArc::Max_Distance);
594 EXPECT_EQ(dist(idx[2], idx[0]), IntDistanceArc::Max_Distance);
595 EXPECT_EQ(dist(idx[3], idx[1]), IntDistanceArc::Max_Distance);
596}
597
599{
601
602 const int N = 5;
603 Graph g;
604 vector<Graph::Node*> nodes;
605
606 for (int i = 0; i < N; ++i)
607 nodes.push_back(g.insert_node(i));
608
609 // Complete graph with all edges having weight 1
610 for (int i = 0; i < N; ++i)
611 for (int j = 0; j < N; ++j)
612 if (i != j)
613 g.insert_arc(nodes[i], nodes[j], IntDistanceArc(1));
614
615 Ady_Mat<Graph, int> dist(g);
616 Ady_Mat<Graph, long> path(g);
617
618 floyd_all_shortest_paths(g, dist, path);
619
620 // In complete graph with unit weights, all distances should be 0 or 1
621 for (long i = 0; i < N; ++i) {
622 for (long j = 0; j < N; ++j) {
623 if (i == j)
624 EXPECT_EQ(dist(i, j), 0);
625 else
626 EXPECT_EQ(dist(i, j), 1);
627 }
628 }
629}
630
631// ============================================================================
632// Custom Compare and Plus Tests
633// ============================================================================
634
635// Max-plus semiring: find widest paths (max of min edge weights)
637{
638 bool operator()(int a, int b) const { return a > b; }
639};
640
642{
643 int operator()(int a, int b) const { return min(a, b); }
644};
645
647{
649
650 Graph g;
651 auto* n0 = g.insert_node(0);
652 auto* n1 = g.insert_node(1);
653 auto* n2 = g.insert_node(2);
654
655 // Path 0->2 direct: capacity 2
656 // Path 0->1->2: min(5, 3) = 3 (better!)
657 g.insert_arc(n0, n1, IntDistanceArc(5));
658 g.insert_arc(n1, n2, IntDistanceArc(3));
659 g.insert_arc(n0, n2, IntDistanceArc(2));
660
661 Ady_Mat<Graph, int> cap(g);
662 Ady_Mat<Graph, long> path(g);
663
664 // Note: This would need a different initialization for max-min
665 // This test just verifies custom functors compile and run
667
668 // The result depends on initialization which assumes min-plus
669 // So we just verify it runs without crashing
670 SUCCEED();
671}
672
673// ============================================================================
674// Stress Test
675// ============================================================================
676
678{
680
681 const int N = 20;
682 Graph g;
683 vector<Graph::Node*> nodes;
684
685 for (int i = 0; i < N; ++i)
686 nodes.push_back(g.insert_node(i));
687
688 // Create a chain with some shortcuts
689 for (int i = 0; i < N - 1; ++i)
690 g.insert_arc(nodes[i], nodes[i + 1], IntDistanceArc(1));
691
692 // Add some shortcuts (longer, so they won't be used)
693 for (int i = 0; i < N - 2; i += 2)
694 g.insert_arc(nodes[i], nodes[i + 2], IntDistanceArc(3)); // Longer than 2 hops
695
696 Ady_Mat<Graph, int> dist(g);
697 Ady_Mat<Graph, long> path(g);
698
699 floyd_all_shortest_paths(g, dist, path);
700
701 // Build index mapping from node info to matrix index
702 vector<long> idx(N, -1);
703 for (long m = 0; m < N; ++m) {
704 int info = dist(m)->get_info();
705 idx[info] = m;
706 }
707
708 // Check that chain distances are correct using proper indices
709 for (int i = 0; i < N; ++i)
710 for (int j = i; j < N; ++j)
711 EXPECT_EQ(dist(idx[i], idx[j]), j - i) << "Distance from " << i << " to " << j;
712}
713
714// ============================================================================
715// Matrix Properties Tests
716// ============================================================================
717
719{
720 Ady_Mat<Graph, Dist> dist(g);
721 Ady_Mat<Graph, long> path(g);
722
723 floyd_all_shortest_paths(g, dist, path);
724
725 const long n = g.get_num_nodes();
726
727 // For reachable nodes, path(i,j) should point to next hop or j itself
728 for (long i = 0; i < n; ++i) {
729 for (long j = 0; j < n; ++j) {
730 if (i == j) {
731 EXPECT_EQ(path(i, j), j) << "Diagonal should point to self";
732 } else if (dist(i, j) < IntDistanceArc::Max_Distance) {
733 long next = path(i, j);
734 EXPECT_GE(next, 0L);
735 EXPECT_LT(next, n);
736 }
737 }
738 }
739}
740
742{
743 Ady_Mat<Graph, Dist> dist(g);
744 Ady_Mat<Graph, long> path(g);
745
746 floyd_all_shortest_paths(g, dist, path);
747
748 const long n = g.get_num_nodes();
749
750 // Triangle inequality: dist(i,j) <= dist(i,k) + dist(k,j)
751 for (long i = 0; i < n; ++i) {
752 for (long j = 0; j < n; ++j) {
753 for (long k = 0; k < n; ++k) {
754 if (!isinf(dist(i, k)) && !isinf(dist(k, j))) {
755 EXPECT_LE(dist(i, j), dist(i, k) + dist(k, j))
756 << "Triangle inequality violated for i=" << i << ", j=" << j << ", k=" << k;
757 }
758 }
759 }
760 }
761}
762
763// ============================================================================
764// Initialize_Dist Tests (implicitly tested via floyd_all_shortest_paths)
765// ============================================================================
766
768{
769 Ady_Mat<Graph, Dist> dist(g);
770 Ady_Mat<Graph, long> path(g);
771
772 // Run Floyd-Warshall which internally uses Initialize_Dist
773 floyd_all_shortest_paths(g, dist, path);
774
775 // After running, we should have valid distances
776 const long n = g.get_num_nodes();
777
778 // Check diagonal is zero (set by initialization)
779 for (long i = 0; i < n; ++i)
780 EXPECT_EQ(dist(i, i), 0);
781
782 // Check that at least some edges have finite weights
783 bool found_finite = false;
784 for (long i = 0; i < n; ++i)
785 for (long j = 0; j < n; ++j)
786 if (i != j && dist(i, j) < IntDistanceArc::Max_Distance)
787 found_finite = true;
788
790}
791
792// ============================================================================
793// Negative Weights (Note: Floyd-Warshall handles them, but not negative cycles)
794// ============================================================================
795
797{
798 // Use double to allow negative values
800
801 Graph g;
802 auto* n0 = g.insert_node(0);
803 auto* n1 = g.insert_node(1);
804 auto* n2 = g.insert_node(2);
805
806 // 0 --1--> 1 ---(-3)---> 2
807 // 0 --2--> 2 (direct, but longer than 0->1->2 = 1 + (-3) = -2)
808 g.insert_arc(n0, n1, DistanceArc(1.0));
809 g.insert_arc(n1, n2, DistanceArc(-3.0)); // Negative weight
810 g.insert_arc(n0, n2, DistanceArc(2.0));
811
813 Ady_Mat<Graph, long> path(g);
814
815 floyd_all_shortest_paths(g, dist, path);
816
817 // Find indices
818 long idx0 = -1, idx2 = -1;
819 for (long i = 0; i < 3; ++i) {
820 if (dist(i)->get_info() == 0) idx0 = i;
821 if (dist(i)->get_info() == 2) idx2 = i;
822 }
823
824 // Shortest 0->2 should be -2 (through 1)
825 EXPECT_DOUBLE_EQ(dist(idx0, idx2), -2.0);
826}
827
828// ============================================================================
829// Large Dense Graph Test
830// ============================================================================
831
833{
835
836 const int N = 10;
837 Graph g;
838 vector<Graph::Node*> nodes;
839
840 for (int i = 0; i < N; ++i)
841 nodes.push_back(g.insert_node(i));
842
843 // Dense graph: edge from i to j with weight (i+j+1) mod N + 1
844 for (int i = 0; i < N; ++i)
845 for (int j = 0; j < N; ++j)
846 if (i != j)
847 g.insert_arc(nodes[i], nodes[j], IntDistanceArc((i + j + 1) % N + 1));
848
849 Ady_Mat<Graph, int> dist(g);
850 Ady_Mat<Graph, long> path(g);
851
852 floyd_all_shortest_paths(g, dist, path);
853
854 // Verify diagonal is zero
855 for (long i = 0; i < N; ++i)
856 EXPECT_EQ(dist(i, i), 0);
857
858 // Verify all pairs are reachable
859 for (long i = 0; i < N; ++i)
860 for (long j = 0; j < N; ++j)
862 << "Should be reachable from " << i << " to " << j;
863}
List_Graph< Node, Arc > Graph
Auxiliary adjacency matrix with custom entry type.
size_t get_num_nodes() const noexcept
Get number of nodes (matrix dimension)
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
typename BaseGraph::Arc Arc
Definition graph-dry.H:3852
typename BaseGraph::Node Node
Definition graph-dry.H:3851
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
Path on a graph.
Definition tpl_graph.H:2669
size_t size() const noexcept
Return the path length in nodes.
Definition tpl_graph.H:2807
Test fixture with integer weights.
vector< Node * > nodes
IntDistanceArc::Distance_Type Dist
void SetUp() override
Test fixture with a simple weighted graph.
long get_index(Ady_Mat< Graph, Dist > &mat, Node *node) const
DistanceArc::Distance_Type Dist
#define TEST(name)
#define N
Definition fib.C:294
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_min_function > > min(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4111
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
void floyd_all_shortest_paths_latex(GT &g, Ady_Mat< GT, typename GT::Arc_Type::Distance_Type > &dist, Ady_Mat< GT, long > &path, std::ofstream &output)
Floyd-Warshall algorithm with LaTeX step-by-step output.
void find_min_path(Mat &p, const long src_index, const long tgt_index, Path< typename Mat::Graph_Type > &path)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void floyd_all_shortest_paths(GT &g, Ady_Mat< GT, typename GT::Arc_Type::Distance_Type > &dist, Ady_Mat< GT, long > &path)
Compute all-pairs shortest paths using Floyd-Warshall algorithm.
Floyd-Warshall algorithm with LaTeX output generation.
TEST_F(FloydSimpleGraphTest, DiagonalIsZero)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Arc info type with required Distance_Type and constants.
Distance_Type get_distance() const
Distance_Type distance
static constexpr Distance_Type Zero_Distance
DistanceArc(Distance_Type d)
static constexpr Distance_Type Max_Distance
Integer distance arc type.
Distance_Type get_distance() const
Distance_Type distance
IntDistanceArc(Distance_Type d)
static constexpr Distance_Type Zero_Distance
static constexpr Distance_Type Max_Distance
bool operator()(int a, int b) const
int operator()(int a, int b) const
Distance formatter: takes matrix, i, j indices, returns formatted entry.
string operator()(Mat &mat, int i, int j) const
Index formatter: takes matrix and index, returns string.
string operator()(Mat &mat, int i) const
Path formatter: takes matrix, i, j indices, returns formatted entry.
string operator()(Mat &mat, int i, int j) const
Generic graph and digraph implementations.
Adjacency matrix representations for graphs.
ofstream output
Definition writeHeap.C:213