Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
maxflow_advanced_example.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
230#include <iostream>
231#include <iomanip>
232#include <chrono>
233#include <vector>
234#include <string>
235#include <cstring>
236#include <tpl_net.H>
237#include <tpl_maxflow.H>
238
239using namespace std;
240using namespace Aleph;
241
242static void usage(const char* prog)
243{
244 cout << "Usage: " << prog
245 << " [--algorithm <edmonds-karp|dinic|capacity-scaling|hlpp>]"
246 << " [--sparse] [--dense] [--help]\n";
247 cout << "\nIf no flags are given, all demos are executed.\n";
248 cout << "If any flags are given, the program always runs the supply chain demo\n";
249 cout << "(using --algorithm if provided) and the large capacities demo.\n";
250 cout << "The grid benchmark comparison is run when --sparse or --dense is set.\n";
251}
252
253static bool has_flag(int argc, char* argv[], const char* flag)
254{
255 for (int i = 1; i < argc; ++i)
256 if (std::strcmp(argv[i], flag) == 0)
257 return true;
258 return false;
259}
260
261static const char* get_opt_value(int argc, char* argv[], const char* opt)
262{
263 for (int i = 1; i + 1 < argc; ++i)
264 if (std::strcmp(argv[i], opt) == 0)
265 return argv[i + 1];
266 return nullptr;
267}
268
269// Type definitions
273
288{
289 Net net;
290
291 auto source = net.insert_node("Source");
292 auto f1 = net.insert_node("Factory1");
293 auto f2 = net.insert_node("Factory2");
294 auto w1 = net.insert_node("Warehouse1");
295 auto w2 = net.insert_node("Warehouse2");
296 auto hub = net.insert_node("Hub");
297 auto sink = net.insert_node("Sink");
298
299 // From source to factories
300 net.insert_arc(source, f1, 12);
301 net.insert_arc(source, f2, 15);
302
303 // Factory to warehouses
304 net.insert_arc(f1, w1, 10);
305 net.insert_arc(f2, w2, 12);
306
307 // Warehouses to hub and sink
308 net.insert_arc(w1, hub, 5);
309 net.insert_arc(w2, hub, 6);
310 net.insert_arc(w1, sink, 8);
311 net.insert_arc(w2, sink, 9);
312
313 // Hub to sink
314 net.insert_arc(hub, sink, 15);
315
316 return net;
317}
318
326Net build_grid_network(int rows, int cols, FlowType base_cap = 10.0)
327{
328 Net net;
329
330 vector<vector<Node*>> nodes(rows, vector<Node*>(cols));
331
332 // Create nodes
333 for (int i = 0; i < rows; ++i)
334 for (int j = 0; j < cols; ++j)
335 nodes[i][j] = net.insert_node("N" + to_string(i) + "_" + to_string(j));
336
337 // Create edges (right and down) with varying capacities
338 for (int i = 0; i < rows; ++i)
339 {
340 for (int j = 0; j < cols; ++j)
341 {
342 // Right edge
343 if (j + 1 < cols)
344 net.insert_arc(nodes[i][j], nodes[i][j+1], base_cap + (i % 3));
345
346 // Down edge
347 if (i + 1 < rows)
348 net.insert_arc(nodes[i][j], nodes[i+1][j], base_cap + (j % 3));
349 }
350 }
351
352 return net;
353}
354
358template <typename Algorithm>
360{
361 // Reset flows
362 for (auto it = net.get_arc_it(); it.has_curr(); it.next())
363 it.get_curr()->flow = 0;
364
365 auto start = chrono::high_resolution_clock::now();
366 FlowType flow = Algorithm()(net);
367 auto end = chrono::high_resolution_clock::now();
368
369 double ms = chrono::duration<double, milli>(end - start).count();
370
371 return {flow, ms};
372}
373
377void print_flow_stats(Net& net, const string& title)
378{
379 cout << "\n=== " << title << " ===" << endl;
380
382 int saturated = 0, zero_flow = 0;
383
384 for (auto it = net.get_arc_it(); it.has_curr(); it.next())
385 {
386 auto* arc = it.get_curr();
387 total_cap += arc->cap;
388 if (arc->flow == arc->cap && arc->cap > 0) saturated++;
389 if (arc->flow == 0) zero_flow++;
390 }
391
392 const FlowType max_flow = net.flow_value();
393
394 cout << "Total capacity: " << total_cap << endl;
395 cout << "Max flow value: " << max_flow << endl;
396 cout << "Saturated arcs: " << saturated << endl;
397 cout << "Zero-flow arcs: " << zero_flow << endl;
398 cout << "Utilization: " << fixed << setprecision(1)
399 << ((total_cap > 0) ? (100.0 * max_flow / total_cap) : 0.0) << "%" << endl;
400}
401
406{
407 cout << "\n=== Flow Decomposition ===" << endl;
408 cout << "Breaking down max-flow into individual paths:\n" << endl;
409
410 auto decomp = decompose_flow(net);
411
412 int path_num = 1;
413 int total_paths = 0;
414
415 for (auto it = decomp.paths.get_it(); it.has_curr(); it.next())
416 {
417 const auto& fp = it.get_curr();
418 cout << "Path " << path_num++ << " (flow = " << fp.flow << "): ";
419 cout << net.get_source()->get_info();
420
421 for (auto ait = fp.arcs.get_it(); ait.has_curr(); ait.next())
422 {
423 auto* arc = ait.get_curr();
424 auto* tgt = net.get_tgt_node(arc);
425 cout << " -> " << tgt->get_info();
426 }
427 cout << endl;
428 ++total_paths;
429 }
430
431 cout << "\nTotal paths: " << total_paths << endl;
432 cout << "Total flow: " << decomp.total_flow() << endl;
433}
434
439{
440 cout << "\n" << string(60, '=') << endl;
441 cout << "Algorithm Comparison on " << grid_size << "x" << grid_size
442 << " Grid Network" << endl;
443 cout << string(60, '=') << endl;
444
446
447 cout << "\nNetwork: " << net.get_num_nodes() << " nodes, "
448 << net.get_num_arcs() << " arcs\n" << endl;
449
450 cout << setw(20) << left << "Algorithm"
451 << setw(12) << right << "Flow"
452 << setw(15) << "Time (ms)" << endl;
453 cout << string(47, '-') << endl;
454
455 // Edmonds-Karp (Ford-Fulkerson with BFS)
456 {
458 cout << setw(20) << left << "Edmonds-Karp"
459 << setw(12) << right << flow
460 << setw(15) << fixed << setprecision(3) << time << endl;
461 }
462
463 // Ford-Fulkerson (augmenting paths with DFS)
464 {
466 cout << setw(20) << left << "Ford-Fulkerson"
467 << setw(12) << right << flow
468 << setw(15) << fixed << setprecision(3) << time << endl;
469 }
470
471 // Dinic
472 {
473 auto [flow, time] = time_algorithm<Dinic_Maximum_Flow<Net>>(net);
474 cout << setw(20) << left << "Dinic"
475 << setw(12) << right << flow
476 << setw(15) << fixed << setprecision(3) << time << endl;
477 }
478
479 // Capacity Scaling
480 {
482 cout << setw(20) << left << "Capacity Scaling"
483 << setw(12) << right << flow
484 << setw(15) << fixed << setprecision(3) << time << endl;
485 }
486
487 // HLPP
488 {
489 auto [flow, time] = time_algorithm<HLPP_Maximum_Flow<Net>>(net);
490 cout << setw(20) << left << "HLPP"
491 << setw(12) << right << flow
492 << setw(15) << fixed << setprecision(3) << time << endl;
493 }
494}
495
500{
501 cout << "\n=== Min-Cut / Max-Flow Duality ===" << endl;
502 cout << "\nThe Max-Flow Min-Cut Theorem states:" << endl;
503 cout << " max_flow = min_cut_capacity" << endl;
504
505 // Find saturated edges (potential min-cut edges)
506 cout << "\nSaturated edges (candidates for min-cut):" << endl;
507
509 for (auto it = net.get_arc_it(); it.has_curr(); it.next())
510 {
511 auto* arc = it.get_curr();
512 if (arc->flow == arc->cap && arc->cap > 0)
513 {
514 auto* src = net.get_src_node(arc);
515 auto* tgt = net.get_tgt_node(arc);
516 cout << " " << src->get_info() << " -> " << tgt->get_info()
517 << " (cap = " << arc->cap << ")" << endl;
518 cut_capacity += arc->cap;
519 }
520 }
521
522 cout << "\nNote: Not all saturated edges are necessarily in the min-cut," << endl;
523 cout << "but the min-cut consists only of saturated edges." << endl;
524}
525
526int main(int argc, char* argv[])
527{
528 cout << "=== Advanced Maximum Flow Algorithms ===" << endl;
529 cout << "Comparing Edmonds-Karp, Ford-Fulkerson, Dinic, Capacity Scaling, and HLPP\n" << endl;
530
531 if (has_flag(argc, argv, "--help"))
532 {
533 usage(argv[0]);
534 return 0;
535 }
536
537 const char* algo = get_opt_value(argc, argv, "--algorithm");
538 const bool sparse = has_flag(argc, argv, "--sparse");
539 const bool dense = has_flag(argc, argv, "--dense");
540
541 const bool has_cli = (argc > 1);
542 const bool default_run_all = !has_cli;
543
544
545 // Demo 1: Supply chain example
546 cout << string(60, '=') << endl;
547 cout << "Demo 1: Supply Chain Network" << endl;
548 cout << string(60, '=') << endl;
549
551
552 cout << "\nNetwork structure:" << endl;
553 cout << " Nodes: " << supply.get_num_nodes() << endl;
554 cout << " Arcs: " << supply.get_num_arcs() << endl;
555
556 FlowType max_flow = 0;
557 const char* chosen = algo ? algo : "dinic";
558 if (std::strcmp(chosen, "dinic") == 0)
559 {
560 cout << "\nComputing max-flow with Dinic's algorithm..." << endl;
561 max_flow = dinic_maximum_flow(supply);
562 }
563 else if (std::strcmp(chosen, "edmonds-karp") == 0)
564 {
565 cout << "\nComputing max-flow with Edmonds-Karp..." << endl;
567 }
568 else if (std::strcmp(chosen, "capacity-scaling") == 0)
569 {
570 cout << "\nComputing max-flow with Capacity Scaling..." << endl;
572 }
573 else if (std::strcmp(chosen, "hlpp") == 0)
574 {
575 cout << "\nComputing max-flow with HLPP..." << endl;
576 max_flow = hlpp_maximum_flow(supply);
577 }
578 else
579 {
580 cout << "Unknown --algorithm value: " << chosen << "\n";
581 usage(argv[0]);
582 return 1;
583 }
584
585 cout << "\n*** Maximum Flow: " << max_flow << " units ***" << endl;
586
587 print_flow_stats(supply, "Flow Statistics");
590
591 if (default_run_all)
592 {
596 }
597 else if (sparse || dense)
598 {
599 const int grid = dense ? 20 : 8;
600 cout << "\nBenchmarking on " << grid << "x" << grid
601 << " grid network\n";
603 }
604
605 // Demo 3: Large capacity handling
606 cout << "\n" << string(60, '=') << endl;
607 cout << "Demo 3: Large Capacities (Capacity Scaling Advantage)" << endl;
608 cout << string(60, '=') << endl;
609
610 Net large_cap = build_grid_network(8, 8, 1000000.0);
611
612 cout << "\nNetwork with capacities around 1,000,000:" << endl;
613
614 cout << setw(20) << left << "Algorithm"
615 << setw(15) << right << "Flow"
616 << setw(15) << "Time (ms)" << endl;
617 cout << string(50, '-') << endl;
618
619 {
621 cout << setw(20) << left << "Ford-Fulkerson"
622 << setw(15) << right << fixed << setprecision(0) << flow
623 << setw(15) << setprecision(3) << time << endl;
624 }
625
626 {
628 cout << setw(20) << left << "Capacity Scaling"
629 << setw(15) << right << fixed << setprecision(0) << flow
630 << setw(15) << setprecision(3) << time << endl;
631 }
632
633 cout << "\nCapacity Scaling excels with large integer capacities!" << endl;
634
635 // Summary
636 cout << "\n" << string(60, '=') << endl;
637 cout << "Summary" << endl;
638 cout << string(60, '=') << endl;
639
640 cout << R"(
641Algorithm Selection Guide:
642
643 1. Edmonds-Karp: O(VE²)
644 - Simple, good for small/sparse graphs
645 - Polynomial in graph size
646
647 2. Dinic: O(V²E)
648 - Excellent all-around choice
649 - Works well on most networks
650
651 3. Capacity Scaling: O(VE log U)
652 - Best for large integer capacities
653 - Scales logarithmically with max capacity
654
655 4. HLPP: O(V²√E)
656 - Push-relabel method
657 - Often fastest in practice for dense graphs
658
659Recommendation:
660 - Start with Dinic (good balance)
661 - Use Capacity Scaling for very large capacities
662 - Use HLPP for dense graphs if Dinic is slow
663)" << endl;
664
665 return 0;
666}
int main()
WeightedDigraph::Node Node
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Definition graph-dry.H:2802
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:731
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
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:737
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
void print_flow_stats(Net &net, const string &title)
Print network flow statistics.
pair< FlowType, double > time_algorithm(Net net)
Time a max-flow algorithm execution.
void compare_algorithms(int grid_size)
Compare all algorithms on the same network.
static void usage(const char *prog)
Net build_grid_network(int rows, int cols, FlowType base_cap=10.0)
Build a grid network for stress testing.
double FlowType
Net build_supply_chain()
Build a supply chain network.
static bool has_flag(int argc, char *argv[], const char *flag)
void demonstrate_flow_decomposition(Net &net)
Demonstrate flow decomposition into paths.
void demonstrate_min_cut(Net &net)
Demonstrate min-cut duality.
static const char * get_opt_value(int argc, char *argv[], const char *opt)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Net::Flow_Type edmonds_karp_maximum_flow(Net &net)
Maximize flow using the Edmonds-Karp algorithm.
Definition tpl_net.H:1551
Net::Flow_Type dinic_maximum_flow(Net &net)
Compute maximum flow using Dinic's algorithm.
FlowDecomposition< Net > decompose_flow(const Net &net)
Decompose network flow into paths and cycles.
Net::Flow_Type capacity_scaling_maximum_flow(Net &net)
Compute maximum flow using capacity scaling.
Net::Flow_Type hlpp_maximum_flow(Net &net)
Compute maximum flow using Highest-Label Preflow-Push.
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
Definition ahPair.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
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Arc of a flow network implemented with adjacency lists.
Definition tpl_net.H:115
Flow network implemented with adjacency lists.
Definition tpl_net.H:261
Node * insert_node(const Node_Type &node_info)
Insert a new node by copying node_info.
Definition tpl_net.H:559
Node * get_source() const
Return an arbitrary source node.
Definition tpl_net.H:548
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
Flow_Type flow_value() const
Return the total flow value of the network.
Definition tpl_net.H:822
NodeT Node
Node type.
Definition tpl_net.H:275
Advanced maximum flow algorithms.
Network flow graph structures.