Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
netcapgraph_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 <random>
40#include <set>
41#include <map>
42#include <string>
43#include <sstream>
44#include <cmath>
45#include <tpl_netcapgraph.H>
46#include <tpl_net.H>
47
48using namespace Aleph;
49using namespace std;
50
51// =============================================================================
52// Type Aliases for Testing
53// =============================================================================
54
58
62
66
67// =============================================================================
68// EDGE CASE TESTS
69// =============================================================================
70
71class NetCapGraphEdgeCases : public ::testing::Test
72{
73protected:
75};
76
77// -----------------------------------------------------------------------------
78// Empty Network Tests
79// -----------------------------------------------------------------------------
80
82{
83 EXPECT_EQ(net.vsize(), 0);
84 EXPECT_EQ(net.esize(), 0);
85 EXPECT_FALSE(net.has_aux_net());
86 EXPECT_EQ(net.get_aux_net(), nullptr);
87}
88
90{
91 // Computing aux net on empty network should succeed but produce empty aux net
92 // or throw - depends on implementation. Let's add nodes first.
93 auto n1 = net.insert_node(10.0);
94 auto n2 = net.insert_node(5.0);
95 net.insert_arc(n1, n2, 15.0, 0.0);
96
97 EXPECT_NO_THROW(net.compute_aux_net());
98 EXPECT_TRUE(net.has_aux_net());
99 net.free_aux_net();
100}
101
102// -----------------------------------------------------------------------------
103// Single Node Tests
104// -----------------------------------------------------------------------------
105
107{
108 auto node = net.insert_node();
109
110 EXPECT_EQ(net.vsize(), 1);
111 EXPECT_EQ(node->max_cap, numeric_limits<double>::max());
112 EXPECT_EQ(node->in_flow, 0.0);
113 EXPECT_EQ(node->out_flow, 0.0);
114}
115
117{
118 auto node = net.insert_node(100.0);
119
120 EXPECT_EQ(node->max_cap, 100.0);
121}
122
124{
125 auto node = net.insert_node(0.0);
126
127 EXPECT_EQ(node->max_cap, 0.0);
128}
129
131{
132 EXPECT_THROW(net.insert_node(-1.0), std::domain_error);
133}
134
135// -----------------------------------------------------------------------------
136// Capacity Boundary Tests
137// -----------------------------------------------------------------------------
138
140{
141 auto node = net.insert_node(numeric_limits<double>::max());
142 EXPECT_EQ(node->max_cap, numeric_limits<double>::max());
143}
144
146{
147 auto node = net.insert_node(numeric_limits<double>::min());
148 EXPECT_EQ(node->max_cap, numeric_limits<double>::min());
149}
150
152{
153 auto node = net.insert_node(numeric_limits<double>::epsilon());
154 EXPECT_EQ(node->max_cap, numeric_limits<double>::epsilon());
155}
156
157// -----------------------------------------------------------------------------
158// Arc Tests
159// -----------------------------------------------------------------------------
160
162{
163 auto n1 = net.insert_node(10.0);
164 auto n2 = net.insert_node(10.0);
165 auto arc = net.insert_arc(n1, n2, 0.0, 0.0);
166
167 EXPECT_EQ(arc->cap, 0.0);
168 EXPECT_EQ(arc->flow, 0.0);
169}
170
172{
173 auto n1 = net.insert_node(10.0);
174 auto n2 = net.insert_node(10.0);
175 auto arc = net.insert_arc(n1, n2, 5.0, 5.0);
176
177 EXPECT_EQ(arc->cap, 5.0);
178 EXPECT_EQ(arc->flow, 5.0);
179}
180
182{
183 auto n1 = net.insert_node(10.0);
184 auto n2 = net.insert_node(10.0);
185
186 EXPECT_THROW(net.insert_arc(n1, n2, 5.0, 10.0), std::overflow_error);
187}
188
189// -----------------------------------------------------------------------------
190// Auxiliary Network Tests
191// -----------------------------------------------------------------------------
192
194{
195 auto n1 = net.insert_node(10.0);
196 auto n2 = net.insert_node(5.0);
197 net.insert_arc(n1, n2, 15.0, 0.0);
198
199 net.compute_aux_net();
200 EXPECT_THROW(net.compute_aux_net(), std::domain_error);
201
202 net.free_aux_net();
203}
204
206{
207 EXPECT_THROW(net.free_aux_net(), std::domain_error);
208}
209
211{
212 EXPECT_THROW(net.update(), std::domain_error);
213}
214
216{
217 auto n1 = net.insert_node(10.0);
218 auto n2 = net.insert_node(5.0);
219 net.insert_arc(n1, n2, 15.0, 0.0);
220
221 // Multiple compute-free cycles should work
222 for (int i = 0; i < 3; ++i)
223 {
224 EXPECT_NO_THROW(net.compute_aux_net());
225 EXPECT_TRUE(net.has_aux_net());
226 EXPECT_NO_THROW(net.free_aux_net());
227 EXPECT_FALSE(net.has_aux_net());
228 }
229}
230
231// -----------------------------------------------------------------------------
232// Copy and Move Tests
233// -----------------------------------------------------------------------------
234
236{
237 auto n1 = net.insert_node(10.0);
238 auto n2 = net.insert_node(5.0);
239 net.insert_arc(n1, n2, 15.0, 3.0);
240
241 DefaultNet copy(net);
242
243 EXPECT_EQ(copy.vsize(), 2);
244 EXPECT_EQ(copy.esize(), 1);
245 EXPECT_FALSE(copy.has_aux_net()); // Aux net is not copied
246}
247
249{
250 auto n1 = net.insert_node(10.0);
251 auto n2 = net.insert_node(5.0);
252 net.insert_arc(n1, n2, 15.0, 3.0);
253 net.compute_aux_net();
254
255 DefaultNet moved(std::move(net));
256
257 EXPECT_EQ(moved.vsize(), 2);
258 EXPECT_EQ(moved.esize(), 1);
259 EXPECT_TRUE(moved.has_aux_net());
260
261 moved.free_aux_net();
262}
263
264// =============================================================================
265// STRUCTURAL TESTS - Various Network Topologies
266// =============================================================================
267
268class NetCapGraphStructure : public ::testing::Test
269{
270protected:
272};
273
274// -----------------------------------------------------------------------------
275// Linear Network (Pipeline)
276// -----------------------------------------------------------------------------
277
279{
280 // A --[10]--> B --[8]--> C
281 // Capacities: A=20, B=5, C=15
282 // Bottleneck should be at B (capacity 5)
283
284 auto a = net.insert_node(20.0);
285 auto b = net.insert_node(5.0);
286 auto c = net.insert_node(15.0);
287
288 net.insert_arc(a, b, 10.0, 0.0);
289 net.insert_arc(b, c, 8.0, 0.0);
290
291 EXPECT_EQ(net.vsize(), 3);
292 EXPECT_EQ(net.esize(), 2);
293
294 auto aux = net.compute_aux_net();
295 EXPECT_NE(aux, nullptr);
296
297 // Aux net should have 2*3 = 6 nodes and 2 + 3 = 5 arcs
298 // (3 node-capacity arcs + 2 edge arcs)
299 EXPECT_EQ(aux->vsize(), 6);
300 EXPECT_EQ(aux->esize(), 5);
301
302 net.free_aux_net();
303}
304
306{
308 for (int i = 0; i < 10; ++i)
309 nodes.push_back(net.insert_node(10.0 + i));
310
311 for (int i = 0; i < 9; ++i)
312 net.insert_arc(nodes[i], nodes[i+1], 5.0 + i, 0.0);
313
314 EXPECT_EQ(net.vsize(), 10);
315 EXPECT_EQ(net.esize(), 9);
316
317 auto aux = net.compute_aux_net();
318 EXPECT_EQ(aux->vsize(), 20); // 2 * 10
319 EXPECT_EQ(aux->esize(), 19); // 10 + 9
320
321 net.free_aux_net();
322}
323
324// -----------------------------------------------------------------------------
325// Star Network (Hub and Spokes)
326// -----------------------------------------------------------------------------
327
329{
330 // Central hub with 5 spokes
331 auto hub = net.insert_node(50.0); // Hub can handle up to 50 flow
332
333 for (int i = 0; i < 5; ++i)
334 {
335 auto spoke = net.insert_node(10.0);
336 net.insert_arc(spoke, hub, 15.0, 0.0); // Incoming to hub
337 }
338
339 EXPECT_EQ(net.vsize(), 6);
340 EXPECT_EQ(net.esize(), 5);
341
342 auto aux = net.compute_aux_net();
343 EXPECT_EQ(aux->vsize(), 12);
344 EXPECT_EQ(aux->esize(), 11);
345
346 net.free_aux_net();
347}
348
349// -----------------------------------------------------------------------------
350// Diamond Network (Parallel Paths)
351// -----------------------------------------------------------------------------
352
354{
355 /*
356 * B
357 * / \
358 * A D
359 * \ /
360 * C
361 */
362
363 auto a = net.insert_node(100.0);
364 auto b = net.insert_node(30.0);
365 auto c = net.insert_node(40.0);
366 auto d = net.insert_node(100.0);
367
368 net.insert_arc(a, b, 50.0, 0.0);
369 net.insert_arc(a, c, 60.0, 0.0);
370 net.insert_arc(b, d, 50.0, 0.0);
371 net.insert_arc(c, d, 60.0, 0.0);
372
373 EXPECT_EQ(net.vsize(), 4);
374 EXPECT_EQ(net.esize(), 4);
375
376 auto aux = net.compute_aux_net();
377 EXPECT_EQ(aux->vsize(), 8);
378 EXPECT_EQ(aux->esize(), 8);
379
380 net.free_aux_net();
381}
382
383// -----------------------------------------------------------------------------
384// Complete Network (All-to-All)
385// -----------------------------------------------------------------------------
386
388{
390 for (int i = 0; i < 5; ++i)
391 nodes.push_back(net.insert_node(20.0));
392
393 for (int i = 0; i < 5; ++i)
394 for (int j = 0; j < 5; ++j)
395 if (i != j)
396 net.insert_arc(nodes[i], nodes[j], 10.0, 0.0);
397
398 EXPECT_EQ(net.vsize(), 5);
399 EXPECT_EQ(net.esize(), 20); // 5 * 4 = 20 directed edges
400
401 auto aux = net.compute_aux_net();
402 EXPECT_EQ(aux->vsize(), 10);
403 EXPECT_EQ(aux->esize(), 25); // 5 node arcs + 20 edge arcs
404
405 net.free_aux_net();
406}
407
408// -----------------------------------------------------------------------------
409// Bipartite Network
410// -----------------------------------------------------------------------------
411
413{
414 // Left side: 3 nodes, Right side: 3 nodes
415 vector<DefaultNet::Node*> left, right;
416
417 for (int i = 0; i < 3; ++i)
418 left.push_back(net.insert_node(10.0));
419
420 for (int i = 0; i < 3; ++i)
421 right.push_back(net.insert_node(15.0));
422
423 // Connect every left to every right
424 for (auto l : left)
425 for (auto r : right)
426 net.insert_arc(l, r, 5.0, 0.0);
427
428 EXPECT_EQ(net.vsize(), 6);
429 EXPECT_EQ(net.esize(), 9);
430
431 auto aux = net.compute_aux_net();
432 EXPECT_EQ(aux->vsize(), 12);
433 EXPECT_EQ(aux->esize(), 15);
434
435 net.free_aux_net();
436}
437
438// =============================================================================
439// REALISTIC SCENARIO TESTS
440// =============================================================================
441
442class NetCapGraphRealistic : public ::testing::Test
443{
444protected:
445 void SetUp() override
446 {
447 rng.seed(42); // Reproducible randomness
448 }
449
451};
452
453// -----------------------------------------------------------------------------
454// Data Center Network Model
455// -----------------------------------------------------------------------------
456
458{
459 // Model:
460 // - 3 data centers (high capacity)
461 // - 10 edge servers (medium capacity)
462 // - Data flows from edge to data centers
463
464 DefaultNet net;
465
466 // Create data centers
468 for (int i = 0; i < 3; ++i)
469 datacenters.push_back(net.insert_node(1000.0)); // High capacity
470
471 // Create edge servers
473 for (int i = 0; i < 10; ++i)
474 edges.push_back(net.insert_node(100.0)); // Medium capacity
475
476 // Connect edges to data centers (each edge connects to 2 data centers)
477 for (int i = 0; i < 10; ++i)
478 {
479 int dc1 = i % 3;
480 int dc2 = (i + 1) % 3;
481 net.insert_arc(edges[i], datacenters[dc1], 50.0, 0.0);
482 net.insert_arc(edges[i], datacenters[dc2], 50.0, 0.0);
483 }
484
485 EXPECT_EQ(net.vsize(), 13);
486 EXPECT_EQ(net.esize(), 20);
487
488 auto aux = net.compute_aux_net();
489 EXPECT_NE(aux, nullptr);
490
491 // Validate structure
492 EXPECT_EQ(aux->vsize(), 26); // 2 * 13
493 EXPECT_EQ(aux->esize(), 33); // 13 + 20
494
495 net.free_aux_net();
496}
497
498// -----------------------------------------------------------------------------
499// Water Distribution Network
500// -----------------------------------------------------------------------------
501
503{
504 // Model:
505 // - 1 reservoir (source, high capacity)
506 // - 3 pumping stations (medium capacity, bottlenecks)
507 // - 10 neighborhoods (sinks)
508
509 DefaultNet net;
510
511 auto reservoir = net.insert_node(10000.0); // High capacity source
512
514 for (int i = 0; i < 3; ++i)
515 pumps.push_back(net.insert_node(2000.0)); // Pumping stations
516
518 for (int i = 0; i < 10; ++i)
519 neighborhoods.push_back(net.insert_node(500.0)); // Consumption nodes
520
521 // Reservoir to pumps
522 for (auto pump : pumps)
523 net.insert_arc(reservoir, pump, 3000.0, 0.0);
524
525 // Pumps to neighborhoods (distributed)
526 for (int i = 0; i < 10; ++i)
527 {
528 int pump_idx = i % 3;
529 net.insert_arc(pumps[pump_idx], neighborhoods[i], 600.0, 0.0);
530 }
531
532 auto aux = net.compute_aux_net();
533 EXPECT_NE(aux, nullptr);
534
535 // Basic structure validation
536 EXPECT_GT(aux->vsize(), 0);
537 EXPECT_GT(aux->esize(), 0);
538
539 net.free_aux_net();
540}
541
542// -----------------------------------------------------------------------------
543// Traffic Network with Intersections
544// -----------------------------------------------------------------------------
545
547{
548 // Model a 4x4 grid of intersections
549 // Each intersection has limited capacity (throughput)
550
551 DefaultNet net;
552 DefaultNet::Node* grid[4][4];
553
554 // Create intersections
555 for (int i = 0; i < 4; ++i)
556 for (int j = 0; j < 4; ++j)
557 grid[i][j] = net.insert_node(100.0); // Each intersection handles 100 cars/min
558
559 // Connect horizontally
560 for (int i = 0; i < 4; ++i)
561 for (int j = 0; j < 3; ++j)
562 {
563 net.insert_arc(grid[i][j], grid[i][j+1], 50.0, 0.0);
564 net.insert_arc(grid[i][j+1], grid[i][j], 50.0, 0.0);
565 }
566
567 // Connect vertically
568 for (int i = 0; i < 3; ++i)
569 for (int j = 0; j < 4; ++j)
570 {
571 net.insert_arc(grid[i][j], grid[i+1][j], 50.0, 0.0);
572 net.insert_arc(grid[i+1][j], grid[i][j], 50.0, 0.0);
573 }
574
575 EXPECT_EQ(net.vsize(), 16);
576 EXPECT_EQ(net.esize(), 48); // 2 * (3*4 + 4*3) = 2 * 24 = 48
577
578 auto aux = net.compute_aux_net();
579 EXPECT_EQ(aux->vsize(), 32);
580 EXPECT_EQ(aux->esize(), 64); // 16 + 48
581
582 net.free_aux_net();
583}
584
585// =============================================================================
586// STRESS TESTS
587// =============================================================================
588
589class NetCapGraphStress : public ::testing::Test
590{
591protected:
592 void SetUp() override
593 {
594 rng.seed(12345);
595 }
596
598};
599
600// -----------------------------------------------------------------------------
601// Large Random Network
602// -----------------------------------------------------------------------------
603
605{
606 DefaultNet net;
607 const int NUM_NODES = 500;
608 const int NUM_ARCS_PER_NODE = 5;
609
613
614 // Create nodes
615 for (int i = 0; i < NUM_NODES; ++i)
616 nodes.push_back(net.insert_node(cap_dist(rng)));
617
618 // Create random arcs
620 for (int i = 0; i < NUM_NODES; ++i)
621 {
622 for (int j = 0; j < NUM_ARCS_PER_NODE; ++j)
623 {
624 int target = node_dist(rng);
625 if (target != i && existing_arcs.find({i, target}) == existing_arcs.end())
626 {
628 net.insert_arc(nodes[i], nodes[target], cap_dist(rng), 0.0);
629 }
630 }
631 }
632
633 EXPECT_EQ(net.vsize(), NUM_NODES);
634 EXPECT_GT(net.esize(), 0);
635
636 // Compute auxiliary network
637 auto aux = net.compute_aux_net();
638 EXPECT_NE(aux, nullptr);
639 EXPECT_EQ(aux->vsize(), 2 * NUM_NODES);
640 EXPECT_EQ(aux->esize(), NUM_NODES + net.esize());
641
642 // Update should not throw
643 EXPECT_NO_THROW(net.update());
644
645 net.free_aux_net();
646}
647
648// -----------------------------------------------------------------------------
649// Deep Chain Network
650// -----------------------------------------------------------------------------
651
653{
654 DefaultNet net;
655 const int CHAIN_LENGTH = 1000;
656
658 nodes.push_back(net.insert_node(100.0));
659
660 for (int i = 1; i < CHAIN_LENGTH; ++i)
661 {
662 nodes.push_back(net.insert_node(100.0));
663 net.insert_arc(nodes[i-1], nodes[i], 50.0, 0.0);
664 }
665
667 EXPECT_EQ(net.esize(), CHAIN_LENGTH - 1);
668
669 auto aux = net.compute_aux_net();
670 EXPECT_EQ(aux->vsize(), 2 * CHAIN_LENGTH);
671
672 net.free_aux_net();
673}
674
675// -----------------------------------------------------------------------------
676// Wide Network (Many Parallel Paths)
677// -----------------------------------------------------------------------------
678
680{
681 DefaultNet net;
682 const int WIDTH = 200;
683
684 auto source = net.insert_node(10000.0);
685 auto sink = net.insert_node(10000.0);
686
687 // Create WIDTH parallel paths of length 3
688 for (int i = 0; i < WIDTH; ++i)
689 {
690 auto mid1 = net.insert_node(50.0);
691 auto mid2 = net.insert_node(50.0);
692
693 net.insert_arc(source, mid1, 100.0, 0.0);
694 net.insert_arc(mid1, mid2, 100.0, 0.0);
695 net.insert_arc(mid2, sink, 100.0, 0.0);
696 }
697
698 EXPECT_EQ(net.vsize(), 2 + 2 * WIDTH);
699 EXPECT_EQ(net.esize(), 3 * WIDTH);
700
701 auto aux = net.compute_aux_net();
702 EXPECT_NE(aux, nullptr);
703
704 net.free_aux_net();
705}
706
707// =============================================================================
708// FLOW CONSERVATION AND VALIDATION TESTS
709// =============================================================================
710
711class NetCapGraphValidation : public ::testing::Test
712{
713protected:
715};
716
718{
719 auto n1 = net.insert_node(10.0);
720 auto n2 = net.insert_node(10.0);
721 auto arc = net.insert_arc(n1, n2, 10.0, 5.0);
722
723 // Manually set some flows
724 n1->in_flow = 3.0;
725 n1->out_flow = 3.0;
726 arc->flow = 5.0;
727
728 net.reset_flows();
729
730 EXPECT_EQ(n1->in_flow, 0.0);
731 EXPECT_EQ(n1->out_flow, 0.0);
732 EXPECT_EQ(arc->flow, 0.0);
733}
734
736{
737 auto n1 = net.insert_node(10.0);
738 auto n2 = net.insert_node(5.0);
739 net.insert_arc(n1, n2, 8.0, 0.0);
740
741 // Set valid flows
742 n1->in_flow = 5.0;
743 n1->out_flow = 5.0;
744 n2->in_flow = 4.0;
745 n2->out_flow = 4.0;
746
747 EXPECT_TRUE(net.check_node_capacities());
748}
749
751{
752 auto n1 = net.insert_node(10.0);
753 auto n2 = net.insert_node(5.0);
754 net.insert_arc(n1, n2, 8.0, 0.0);
755
756 // Set invalid flows (exceeds n2 capacity)
757 n1->in_flow = 8.0;
758 n1->out_flow = 8.0;
759 n2->in_flow = 8.0; // Exceeds capacity of 5
760 n2->out_flow = 8.0;
761
762 EXPECT_FALSE(net.check_node_capacities());
763}
764
766{
767 auto node = net.insert_node(10.0);
768 node->in_flow = 5.0;
769 node->out_flow = 5.0;
770
771 // Setting capacity >= current flow should work
773 EXPECT_EQ(node->max_cap, 5.0);
774}
775
777{
778 auto node = net.insert_node(10.0);
779 node->in_flow = 5.0;
780 node->out_flow = 5.0;
781
782 // Setting capacity < current flow should throw
783 EXPECT_THROW(DefaultNet::set_node_cap(node, 4.0), std::overflow_error);
784}
785
787{
788 auto node = net.insert_node(10.0);
789
790 EXPECT_THROW(DefaultNet::set_node_cap(node, -1.0), std::domain_error);
791}
792
793// =============================================================================
794// INTEGER FLOW TYPE TESTS
795// =============================================================================
796
797class NetCapGraphIntegerFlow : public ::testing::Test
798{
799protected:
801};
802
804{
805 auto n1 = net.insert_node(0, 100L);
806 auto n2 = net.insert_node(0, 50L);
807 auto arc = net.insert_arc(n1, n2, 75L, 0L);
808
809 EXPECT_EQ(n1->max_cap, 100L);
810 EXPECT_EQ(n2->max_cap, 50L);
811 EXPECT_EQ(arc->cap, 75L);
812}
813
815{
816 auto n1 = net.insert_node(0, 100L);
817 auto n2 = net.insert_node(0, 50L);
818 net.insert_arc(n1, n2, 75L, 0L);
819
820 auto aux = net.compute_aux_net();
821 EXPECT_NE(aux, nullptr);
822
823 net.free_aux_net();
824}
825
826// =============================================================================
827// STRING INFO TYPE TESTS
828// =============================================================================
829
830class NetCapGraphStringInfo : public ::testing::Test
831{
832protected:
834};
835
837{
838 auto n1 = net.insert_node("Source", 100.0);
839 auto n2 = net.insert_node("Sink", 50.0);
840 auto arc = net.insert_arc(n1, n2, 75.0, 0.0, "Connection");
841
842 EXPECT_EQ(n1->get_info(), "Source");
843 EXPECT_EQ(n2->get_info(), "Sink");
844 EXPECT_EQ(arc->get_info(), "Connection");
845}
846
848{
849 auto n1 = net.insert_node("Node_A", 100.0);
850 auto n2 = net.insert_node("Node_B", 50.0);
851 net.insert_arc(n1, n2, 75.0, 0.0);
852
853 auto aux = net.compute_aux_net();
854 EXPECT_NE(aux, nullptr);
855
856 net.free_aux_net();
857}
858
859// =============================================================================
860// COOKIE MAPPING TESTS
861// =============================================================================
862
863class NetCapGraphCookies : public ::testing::Test
864{
865protected:
867};
868
870{
871 auto n1 = net.insert_node(10.0);
872 auto n2 = net.insert_node(20.0);
873 net.insert_arc(n1, n2, 15.0, 0.0);
874
875 net.compute_aux_net();
876
877 // NODE_COOKIE(n1) should point to an arc in aux_net
878 auto cookie1 = NODE_COOKIE(n1);
879 auto cookie2 = NODE_COOKIE(n2);
880
881 EXPECT_NE(cookie1, nullptr);
882 EXPECT_NE(cookie2, nullptr);
883
884 // ARC_COOKIE of that arc should point back to n1
885 using AuxArc = typename DefaultNet::Aux_Net::Arc;
886 auto aux_arc1 = static_cast<AuxArc*>(cookie1);
888
889 net.free_aux_net();
890}
891
893{
894 auto n1 = net.insert_node(10.0);
895 auto n2 = net.insert_node(20.0);
896 auto arc = net.insert_arc(n1, n2, 15.0, 0.0);
897
898 net.compute_aux_net();
899
900 // ARC_COOKIE(arc) should point to an arc in aux_net
901 auto cookie = ARC_COOKIE(arc);
902 EXPECT_NE(cookie, nullptr);
903
904 // That aux arc should point back to arc
905 using AuxArc = typename DefaultNet::Aux_Net::Arc;
906 auto aux_arc = static_cast<AuxArc*>(cookie);
908
909 net.free_aux_net();
910}
911
912// =============================================================================
913// FUZZ TESTS
914// =============================================================================
915
916class NetCapGraphFuzz : public ::testing::Test
917{
918protected:
919 void SetUp() override
920 {
921 rng.seed(98765);
922 }
923
925};
926
928{
929 DefaultNet net;
930
933
935
936 // Perform 1000 random operations
937 for (int i = 0; i < 1000; ++i)
938 {
939 int op = op_dist(rng);
940
941 if (nodes.size() < 2 || op == 0)
942 {
943 // Insert node
944 auto node = net.insert_node(cap_dist(rng));
945 nodes.push_back(node);
946 }
947 else if (op == 1 && nodes.size() >= 2)
948 {
949 // Insert arc between random nodes
951 size_t src_idx = node_dist(rng);
952 size_t tgt_idx = node_dist(rng);
953 if (src_idx != tgt_idx)
954 {
955 try
956 {
958 }
959 catch (...)
960 {
961 // Ignore duplicate arc errors
962 }
963 }
964 }
965 else if (op == 2 && !net.has_aux_net() && nodes.size() >= 2)
966 {
967 // Compute and free aux net
968 try
969 {
970 net.compute_aux_net();
971 net.update();
972 net.free_aux_net();
973 }
974 catch (...)
975 {
976 // May fail if network structure is invalid
977 }
978 }
979 }
980
981 // Cleanup
982 if (net.has_aux_net())
983 net.free_aux_net();
984
985 EXPECT_GT(net.vsize(), 0);
986}
987
989{
990 DefaultNet net;
991
992 // Test with extreme capacity values
993 vector<double> extreme_caps = {
994 0.0,
995 numeric_limits<double>::min(),
996 numeric_limits<double>::epsilon(),
997 1e-300,
998 1e-10,
999 1.0,
1000 1e10,
1001 1e100,
1002 1e300,
1003 numeric_limits<double>::max() / 2, // Avoid overflow in aux net
1004 };
1005
1007 for (double cap : extreme_caps)
1008 nodes.push_back(net.insert_node(cap));
1009
1010 // Connect consecutive nodes
1011 for (size_t i = 0; i < nodes.size() - 1; ++i)
1012 net.insert_arc(nodes[i], nodes[i+1], extreme_caps[i], 0.0);
1013
1015 net.compute_aux_net();
1016 net.update();
1017 net.free_aux_net();
1018 });
1019}
1020
1021// =============================================================================
1022// Main entry point
1023// =============================================================================
1024
1025int main(int argc, char **argv)
1026{
1027 ::testing::InitGoogleTest(&argc, argv);
1028 return RUN_ALL_TESTS();
1029}
int main()
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
void * insert_arc(void *arc)
Definition tpl_agraph.H:141
static void set_node_cap(Node *node, const Flow_Type &cap)
Set the capacity of a node.
bool has_aux_net() const noexcept
Check if auxiliary network has been computed.
void free_aux_net()
Free the auxiliary network.
void update()
Update flow values from auxiliary network to this network.
Node * insert_node(Node *p) override
Aux_Net * compute_aux_net()
Compute the equivalent arc-capacitated auxiliary network.
Node with capacity constraint for flow networks.
Node with supply/demand flow value.
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
void SetUp() override
void SetUp() override
iterator end() noexcept
Return an STL-compatible end iterator.
static mt19937 rng
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
#define ARC_COOKIE(p)
Return the arc cookie
#define NODE_COOKIE(p)
Return the node cookie
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.
STL namespace.
TEST_F(NetCapGraphEdgeCases, EmptyNetwork_NoNodes)
#define WIDTH(p)
Definition ntreepic.C:361
Arc * insert_arc(Node *src_node, Node *tgt_node, const Flow_Type &cap, const Flow_Type &flow, const typename Arc::Arc_Type &arc_info=Arc_Type())
Insert a capacitated arc with an initial flow.
Definition tpl_net.H:607
Network flow graph structures.
Network flow graph with capacities.
DynList< int > l