Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_netcost.H
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# ifndef TPL_NETCOST_H
49# define TPL_NETCOST_H
50
51# include <ah-graph-concepts.H>
52
53# include <limits>
54# include <chrono>
55# include <tpl_net.H>
56# include <tpl_dynMapTree.H>
57# include <tpl_find_path.H>
58# include <tpl_cut_nodes.H>
59# include <Bellman_Ford.H>
60# include <generate_graph.H>
61# include <ah-errors.H>
62
63namespace Aleph
64{
72 template <typename Node_Info = Empty_Class>
74
75
93 template <typename Arc_Info = Empty_Class, typename F_Type = double>
94 struct Net_Cost_Arc : public Net_Arc<Arc_Info, F_Type>
95 {
97 using Base::Base;
98
101
104
106 Net_Cost_Arc() = default;
107
110 : Base(a), cost(a.cost)
111 { /* empty */
112 }
113
116 {
117 if (&a == this)
118 return *this;
120 cost = a.cost;
121 return *this;
122 }
123
126 };
127
128
146 template <class NodeT = Net_Cost_Node<Empty_Class>,
147 class ArcT = Net_Cost_Arc<Empty_Class, double>>
148 struct Net_Cost_Graph : public Net_Graph<NodeT, ArcT>
149 {
151
154
157
159 using Arc = ArcT;
160
162 using Node = NodeT;
163
165 using Flow_Type = typename Arc::Flow_Type;
166
168 using Node_Type = typename Node::Node_Type;
169
171 using Arc_Type = typename Arc::Arc_Type;
172
174 Net_Cost_Graph() = default;
175
184 {
185 zip(this->arcs(), net.arcs()).for_each([](const auto & p)
186 {
187 auto atgt = p.first;
188 auto asrc = p.second;
189 atgt->cost = asrc->cost;
190 });
191 }
192
195
198 {
199 if (this == &net)
200 return *this;
201 Net_Cost_Graph tmp(net); // copy construct (copies capacity, flow, and cost)
202 this->swap(tmp); // swap with copy
203 return *this;
204 }
205
208
214 Flow_Type &get_cost(Arc *a) noexcept { return a->cost; }
215
221 Flow_Type get_cost(Arc *a) const noexcept { return a->cost; }
222
228 static Flow_Type arc_flow_cost(Arc *a) noexcept { return a->flow_cost(); }
229
241 virtual Arc * insert_arc(Node *src_node, Node *tgt_node,
242 const Flow_Type & cap, const Flow_Type & __cost)
243 {
244 Arc *a = Net::insert_arc(src_node, tgt_node, cap, 0, Arc_Type());
245 a->cost = __cost;
246 return a;
247 }
248
259 template <typename... Args>
260 Arc * emplace_arc(Node *src_node, Node *tgt_node,
261 const Flow_Type & cap, const Flow_Type & __cost,
262 Args &&... args)
263 {
264 auto a = Net::insert_arc(src_node, tgt_node, cap, 0,
265 Arc_Type(std::forward<Args>(args)...));
266 a->cost = __cost;
267 return a;
268 }
269
279 virtual Arc * insert_arc(Node *src_node, Node *tgt_node)
280 {
281 Arc *a = Net::insert_arc(src_node, tgt_node, Arc_Type());
282 a->cost = 0;
283 return a;
284 }
285
293 {
294 Flow_Type total = 0;
295 for (Arc_Iterator<Net_MFMC> it(*this); it.has_curr(); it.next_ne())
296 {
297 Arc *a = it.get_curr();
298 total += a->flow_cost();
299 }
300 return total;
301 }
302
309 auto out_pars(Node *p)
310 {
311 Flow_Type cap_sum = 0, flow_sum = 0, cost_sum = 0;
312 for (_Out_Iterator<Net> it(p); it.has_curr(); it.next_ne())
313 {
314 Arc *a = it.get_curr();
315 cap_sum += a->cap;
316 flow_sum += a->flow;
317 cost_sum += a->cost;
318 }
319 return std::make_tuple(cap_sum, flow_sum, cost_sum);
320 }
321
328 auto in_pars(Node *p)
329 {
330 Flow_Type cap_sum = 0, flow_sum = 0, cost_sum = 0;
331 for (_In_Iterator<Net> it(p); it.has_curr(); it.next_ne())
332 {
333 Arc *a = it.get_curr();
334 cap_sum += a->cap;
335 flow_sum += a->flow;
336 cost_sum += a->cost;
337 }
338 return std::make_tuple(cap_sum, flow_sum, cost_sum);
339 }
340 };
341
342
350 template <class Net>
351 struct Res_Filt
352 {
354 Res_Filt(typename Net::Node *) noexcept {}
355
358
365 {
366 return a->cap > a->flow;
367 }
368 };
369
370
379 template <class Net>
380 struct Rcost
381 {
383
385
392 {
393 return a->cost;
394 }
395
402 static void set_zero(typename Net::Arc *a) noexcept
403 {
404 a->cap = std::numeric_limits<Distance_Type>::max();
405 a->flow = 0;
406 a->cost = 0;
407 }
408 };
409
410
419 template <typename Ftype>
420 struct Res_Arc : public Net_Cost_Arc<Empty_Class, Ftype>
421 {
423 using Base::Base;
424
426 bool is_residual = false;
427
429 Res_Arc *img = nullptr;
430 };
431
432
438 template <typename Ftype>
440
441
460 template <class Res_Net>
461 typename Res_Net::Arc *
463 typename Res_Net::Node *src,
464 typename Res_Net::Node *tgt,
465 const typename Res_Net::Flow_Type cap,
466 const typename Res_Net::Flow_Type flow,
467 const typename Res_Net::Flow_Type cost)
468 {
470
471 auto arc = residual_net.insert_arc(src, tgt, cap, cost);
472 auto rarc = residual_net.insert_arc(tgt, src, cap, -cost);
473
474 arc->is_residual = false;
475 arc->flow = flow;
476 arc->img = rarc;
477
478 rarc->is_residual = true;
479 rarc->img = arc;
480 rarc->flow = arc->cap - arc->flow;
481
482 assert(arc->cap == cap and arc->flow == flow and arc->cost == cost);
483 assert(rarc->cap == cap and rarc->flow == cap - flow and rarc->cost == -cost);
484
485 return arc;
486 }
487
488
504 template <class Net>
509 {
511 << "Network is not single source and single sink";
512
514
515 // Copy nodes from net to residual network
516 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
517 {
518 auto p = it.get_curr();
519 auto q = rnet.insert_node();
521 }
522
523 // Create residual arcs and build mapping
524 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
525 {
526 auto ga = it.get_curr();
527 auto gsrc = static_cast<typename Net::Node *>(ga->src_node);
528 auto gtgt = static_cast<typename Net::Node *>(ga->tgt_node);
529
533 ga->cap, ga->flow, ga->cost);
534 arcs.insert(ga, ra);
535 }
536
538
539 return static_cast<typename Rnet::Node *>(NODE_COOKIE(net.get_source()));
540 }
541
542
552 template <class Res_Net>
553 bool check_residual_net(const Res_Net & net)
554 {
555 return net.all_arcs([](typename Res_Net::Arc *a)
556 {
557 return a->img != nullptr and a->img->img == a;
558 });
559 }
560
561
574 template <class Res_Net>
575 void cancel_cycle(const Res_Net &, const Path<Res_Net> & path)
576 {
578 << "Path is empty or not a cycle";
579
580 using Ftype = typename Res_Net::Flow_Type;
581
582 // Determine minimum slack (bottleneck capacity) of the cycle
583 Ftype slack = std::numeric_limits<Ftype>::max();
584 path.for_each_arc([&slack](typename Res_Net::Arc *a)
585 {
586 assert(a->cap - a->flow > 0);
587 slack = std::min(slack, a->cap - a->flow);
588 });
589
590 // Cancel the cycle by augmenting flow
591 path.for_each_arc([slack](typename Res_Net::Arc *a)
592 {
593 auto img = a->img;
594 assert(img->img == a);
595 assert(a->cap == img->cap);
596 a->flow += slack;
597 img->flow -= slack;
598 });
599 }
600
601
611 template <class Net>
613 {
615 arcs.for_each([](std::pair<void *, void *> p)
616 {
617 auto net_arc = static_cast<typename Net::Arc *>(p.first);
618 auto res_arc = static_cast<typename Rnet::Arc *>(p.second);
619 net_arc->flow = res_arc->flow;
620 });
621 }
622
623
667 template <FlowNetwork Net,
668 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
669 std::tuple<size_t, double>
671 double it_factor = 0.4,
672 size_t step = 10)
673 {
674 Max_Flow_Algo<Net>()(net); // First compute maximum flow
675
679
680 // Build residual network
681 Rnet rnet;
683 typename Rnet::Node *source = build_residual_net(net, rnet, arcs_map);
684
685 size_t count = 0;
686 bool found_cycle = true;
687
688 // Main loop: find and cancel negative cycles
689 while (found_cycle)
690 {
691 // Search for negative cycle from source
692 auto [cycle, iterations] =
693 BF(rnet).search_negative_cycle(source, it_factor, step);
694
695 if (cycle.is_empty())
696 {
697 // No cycle found from source, try global search
698 auto [global_cycle, global_iter] =
699 BF(rnet).search_negative_cycle(it_factor, step);
700
701 if (global_cycle.is_empty())
702 found_cycle = false;
703 else
704 {
706 ++count;
707 }
708 }
709 else
710 { // Update iteration factor based on when cycle was found
711 it_factor = static_cast<double>(iterations) / net.vsize();
713 ++count;
714 }
715 }
716
717 // Transfer results back to original network
719
720 return std::make_tuple(count, it_factor);
721 }
722
723
734 template <FlowNetwork Net,
735 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
737 {
745 std::tuple<size_t, double> operator ()(Net & net,
746 const double it_factor = 0.4,
747 const size_t step = 10)
748 {
750 (net, it_factor, step);
751 }
752 };
753
754
765 template <class Net>
766 void print_net_cost(const Net & net, std::ostream & out)
767 {
768 long i = 0;
769 net.nodes().for_each([&i](typename Net::Node *p)
770 {
771 NODE_COUNTER(p) = i++;
772 });
773
774 struct Show_Node
775 {
776 void operator ()(const Net &, typename Net::Node *p, std::ostream & o)
777 {
778 o << "label = \"(" << p->get_info() << "," << NODE_COUNTER(p) << ")\"";
779 }
780 };
781
782 struct Show_Arc
783 {
784 void operator ()(const Net &, typename Net::Arc *a, std::ostream & o)
785 {
786 o << "label = \"" << a->flow << "/" << a->cap << "/" << a->cost << "\"";
787 }
788 };
789
791 }
792
793
803 template <class Net>
805 std::ostream & out)
806 {
808
809 long i = 0;
810 net.nodes().for_each([&i](typename Rnet::Node *p)
811 {
812 NODE_COUNTER(p) = i++;
813 });
814
815 struct Show_Node
816 {
817 void operator ()(const Rnet &, typename Rnet::Node *p, std::ostream & o)
818 {
819 o << "label = \"" << NODE_COUNTER(p) << "\"";
820 }
821 };
822
823 struct Show_Arc
824 {
825 void operator ()(const Rnet &, typename Rnet::Arc *a, std::ostream & o)
826 {
827 o << "label = \"" << a->flow << "/" << a->cap << "/" << a->cost << "\"";
828 if (a->is_residual)
829 o << " color = red";
830 }
831 };
832
834 Res_Filt<Rnet>>().digraph(net, out);
835 }
836
837
838 // =========================================================================
839 // Network Simplex Algorithm Implementation
840 // =========================================================================
841
852 template <class Net>
853 using Feasible_Tree = std::tuple<DynList<typename Net::Arc *>,
856
857
867 template <class Net>
869 {
870 using Arc = typename Net::Arc;
871 DynList<Arc *> empty, full, partial;
872
873 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
874 {
875 if (auto a = it.get_curr(); a->flow == 0)
876 empty.append(a);
877 else if (a->flow == a->cap)
878 full.append(a);
879 else
880 partial.append(a);
881 }
882
883 return std::make_tuple(std::move(empty), std::move(full), std::move(partial));
884 }
885
886
894 template <class Net>
896 {
898 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
899 if (auto a = it.get_curr(); a->flow > 0 and a->flow < a->cap)
900 ret.append(a);
901 return ret;
902 }
903
904
914 template <typename Ftype>
916 {
919
921 void *parent = nullptr;
922
924 void *parent_arc = nullptr;
925
927 long depth = 0;
928
930 bool arc_from_parent = true;
931
933 long mark = 0;
934 };
935
936
942 enum class Simplex_Arc_State : unsigned char
943 {
944 Lower,
945 Upper,
946 Tree
947 };
948
949
955 template <typename Ftype>
965
966
973 {
974 size_t total_pivots = 0;
975 size_t phase1_pivots = 0;
976 size_t phase2_pivots = 0;
977 size_t degenerate_pivots = 0;
978 size_t tree_arcs = 0;
979 double phase1_time_ms = 0.0;
980 double phase2_time_ms = 0.0;
981 double total_time_ms = 0.0;
983 size_t forced_into_tree = 0;
984
986 {
987 total_pivots = 0;
988 phase1_pivots = 0;
989 phase2_pivots = 0;
991 tree_arcs = 0;
992 phase1_time_ms = 0.0;
993 phase2_time_ms = 0.0;
994 total_time_ms = 0.0;
997 }
998 };
999
1000
1041 template <FlowNetwork Net>
1043 {
1044 public:
1045 using Node = typename Net::Node;
1046 using Arc = typename Net::Arc;
1047 using Flow_Type = typename Net::Flow_Type;
1050
1051 private:
1057 Node *root = nullptr;
1058 size_t num_pivots = 0;
1059 long lca_mark = 0; // Counter for LCA marking
1062
1063 static constexpr Flow_Type Inf = std::numeric_limits<Flow_Type>::max();
1064
1067 {
1068 if constexpr (std::is_floating_point_v<Flow_Type>)
1069 return std::numeric_limits<Flow_Type>::epsilon() * 1000;
1070 else
1071 return 0;
1072 }
1073
1076
1078 const Node_Info &ninfo(Node *p) const { return node_info(node_to_idx.find(p)); }
1079
1082
1084 const Arc_Info &ainfo(Arc *a) const { return arc_info(arc_to_idx.find(a)); }
1085
1087 Node *parent(Node *p) const { return static_cast<Node *>(ninfo(p).parent); }
1088
1090 Arc *parent_arc(Node *p) const { return static_cast<Arc *>(ninfo(p).parent_arc); }
1091
1093 long depth(Node *p) const { return ninfo(p).depth; }
1094
1096 Flow_Type potential(Node *p) const { return ninfo(p).potential; }
1097
1099 bool is_zero(Flow_Type x) const
1100 {
1101 if constexpr (std::is_floating_point_v<Flow_Type>)
1102 return std::abs(x) <= eps();
1103 else
1104 return x == 0;
1105 }
1106
1112 {
1113 auto src = static_cast<Node *>(a->src_node);
1114 auto tgt = static_cast<Node *>(a->tgt_node);
1115 return a->cost - ninfo(src).potential + ninfo(tgt).potential;
1116 }
1117
1120 {
1121 node_info.cut(0);
1122 arc_info.cut(0);
1124 arc_to_idx.empty();
1125
1126 // Map nodes to indices
1127 size_t idx = 0;
1128 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
1129 {
1130 auto p = it.get_curr();
1131 node_to_idx.insert(p, idx);
1132 node_info.touch(idx) = Node_Info{};
1133 ++idx;
1134 }
1135
1136 // Map arcs to indices - DO NOT classify yet, let build_spanning_tree handle it
1137 idx = 0;
1138 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1139 {
1140 auto a = it.get_curr();
1141 arc_to_idx.insert(a, idx);
1142 arc_info.touch(idx) = Arc_Info{};
1143 // Initially mark all arcs as Lower; build_spanning_tree will fix this
1145 ++idx;
1146 }
1147 }
1148
1150 bool is_partial_flow(Arc *a) const
1151 {
1152 return a->flow > eps() and a->flow < a->cap - eps();
1153 }
1154
1164 {
1165 root = net.get_source();
1166
1167 // Reset all nodes
1168 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
1169 {
1170 auto p = it.get_curr();
1171 auto &ni = ninfo(p);
1172 ni.parent = nullptr;
1173 ni.parent_arc = nullptr;
1174 ni.depth = -1;
1175 ni.potential = 0;
1176 ni.mark = 0;
1177 }
1178
1179 // Reset all arcs to Lower
1180 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1181 ainfo(it.get_curr()).state = Simplex_Arc_State::Lower;
1182
1183 const size_t total_nodes = net.vsize();
1185 queue.put(root);
1186 ninfo(root).depth = 0;
1187 ninfo(root).potential = 0;
1188
1189 size_t nodes_in_tree = 1;
1190
1191 // Helper to add a node to tree via an arc
1192 auto add_to_tree = [&](Node *p, Arc *a, Node *other) -> bool {
1193 if (ninfo(other).depth >= 0)
1194 return false; // Already in tree
1195
1196 const auto &pi = ninfo(p);
1197 auto &oi = ninfo(other);
1198 oi.parent = p;
1199 oi.parent_arc = a;
1200 oi.depth = pi.depth + 1;
1201
1202 auto src = static_cast<Node *>(a->src_node);
1203 if (src == p)
1204 {
1205 oi.arc_from_parent = true;
1206 oi.potential = pi.potential - a->cost;
1207 }
1208 else
1209 {
1210 oi.arc_from_parent = false;
1211 oi.potential = pi.potential + a->cost;
1212 }
1213
1215 ++nodes_in_tree;
1216 queue.put(other);
1217 return true;
1218 };
1219
1220 // Build tree with multiple priority passes
1221 while (not queue.is_empty() and nodes_in_tree < total_nodes)
1222 {
1223 auto p = queue.get();
1224
1225 // Collect all candidate arcs with priorities
1226 struct ArcPriority {
1227 Arc* arc;
1228 Node* other;
1229 int priority; // 0 = partial flow, 1 = with flow, 2 = no flow
1230 };
1232
1233 for (Node_Arc_Iterator<Net> it(p); it.has_curr(); it.next_ne())
1234 {
1235 auto a = it.get_curr();
1236 auto other = net.get_connected_node(a, p);
1237 if (ninfo(other).depth >= 0)
1238 continue; // Already in tree
1239
1240 int prio;
1241 if (is_partial_flow(a))
1242 prio = 0; // Highest priority
1243 else if (a->flow > eps())
1244 prio = 1; // Medium priority
1245 else
1246 prio = 2; // Lowest priority
1247
1248 candidates.append(ArcPriority{a, other, prio});
1249 }
1250
1251 // Sort by priority (partial flow first)
1252 // Since DynList doesn't have sort, process in order
1253 for (int target_prio = 0; target_prio <= 2; ++target_prio)
1254 {
1255 for (auto& ap : candidates)
1256 {
1257 if (ap.priority == target_prio)
1258 add_to_tree(p, ap.arc, ap.other);
1259 }
1260 }
1261 }
1262
1263 // Classify remaining non-tree arcs
1264 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1265 {
1266 auto a = it.get_curr();
1267 if (ainfo(a).state == Simplex_Arc_State::Tree)
1268 continue;
1269
1270 if (a->flow <= eps())
1272 else if (a->flow >= a->cap - eps())
1274 else
1275 {
1276 // Partial flow arc NOT in tree - classify based on reduced cost
1277 auto rc = reduced_cost(a);
1278 ainfo(a).state = (rc < -eps()) ?
1280 }
1281 }
1282 }
1283
1301 {
1302 Arc *best = nullptr;
1303 Flow_Type best_violation = eps(); // Threshold to avoid tiny violations
1304 bool best_is_increase = true;
1305
1306 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1307 {
1308 auto a = it.get_curr();
1309 auto &ai = ainfo(a);
1310
1311 if (ai.state == Simplex_Arc_State::Tree)
1312 continue;
1313
1314 if (ai.skip) // Skip arcs that failed in this round
1315 continue;
1316
1317 const auto rc = reduced_cost(a);
1318 const bool can_increase = (a->flow < a->cap - eps());
1319 const bool can_decrease = (a->flow > eps());
1320
1321 // Check FORWARD direction: increase flow (rc < 0 is good)
1323 {
1324 best_violation = -rc;
1325 best = a;
1326 best_is_increase = true;
1327 }
1328
1329 // Check BACKWARD direction: decrease flow (rc > 0 is good)
1330 // This is equivalent to using the "reverse arc" in residual network
1332 {
1334 best = a;
1335 best_is_increase = false;
1336 }
1337 }
1338
1339 // Update state based on direction
1340 if (best != nullptr)
1341 {
1344 }
1345
1346 return best;
1347 }
1348
1358 {
1359 ++lca_mark; // Use new mark
1360
1361 // Mark path from u to root
1362 Node *p = u;
1363 while (p != nullptr)
1364 {
1365 ninfo(p).mark = lca_mark;
1366 p = parent(p);
1367 }
1368
1369 // Walk from v towards root until we hit a marked node
1370 p = v;
1371 while (p != nullptr and ninfo(p).mark != lca_mark)
1372 p = parent(p);
1373
1374 return p;
1375 }
1376
1398 {
1399 auto u = static_cast<Node *>(entering->src_node);
1400 auto v = static_cast<Node *>(entering->tgt_node);
1401 Node *lca = find_lca(u, v);
1402
1403 assert(lca != nullptr);
1404
1405 // Determine if we're increasing or decreasing flow on entering arc
1406 const bool increase_on_entering = (ainfo(entering).state == Simplex_Arc_State::Lower);
1407
1408 // Count arcs in the cycle and check if it's a valid cycle
1409 // A valid cycle must have at least one arc where flow increases
1410 // and at least one where flow decreases (in the cycle direction)
1411 size_t arcs_with_increase = 0;
1412 size_t arcs_with_decrease = 0;
1413 size_t total_cycle_arcs = 1; // Start with entering arc
1414
1417 else
1419
1420
1421 // Walk from u to lca and count
1422 Node *p = u;
1423 while (p != lca)
1424 {
1427
1428 if (flow_increases)
1430 else
1432
1434 p = parent(p);
1435 }
1436
1437 // Walk from v to lca and count
1438 p = v;
1439 while (p != lca)
1440 {
1443
1444 if (flow_increases)
1446 else
1448
1450 p = parent(p);
1451 }
1452
1453 // If the cycle only has one arc (the entering arc itself) or
1454 // all arcs go in the same direction, it's not a valid cycle
1455 // for flow redistribution
1457 {
1458 delta = 0;
1459 leaving = entering;
1461 return false; // No valid pivot possible
1462 }
1463
1464 // Initialize with entering arc's slack
1466 delta = entering->cap - entering->flow;
1467 else
1468 delta = entering->flow;
1469
1470 leaving = entering;
1472
1473 // Walk from u to lca
1474 // Direction: lca → ... → u (following tree direction)
1475 // If increase_on_entering, flow increases in arcs pointing towards u
1476 p = u;
1477 while (p != lca)
1478 {
1479 Arc *pa = parent_arc(p);
1481 // from_parent=true means arc goes parent→child (towards u)
1482 // So flow increases when both are true or both are false
1484
1486 bool goes_lower;
1487
1488 if (flow_increases)
1489 {
1490 slack = pa->cap - pa->flow;
1491 goes_lower = false;
1492 }
1493 else
1494 {
1495 slack = pa->flow;
1496 goes_lower = true;
1497 }
1498
1499 // Prefer arc that goes to lower bound in case of tie (Bland's rule variant)
1500 if (slack < delta or (slack == delta and goes_lower and not leaving_goes_lower))
1501 {
1502 delta = slack;
1503 leaving = pa;
1505 }
1506
1507 p = parent(p);
1508 }
1509
1510 // Walk from v to lca
1511 // Direction: v → ... → lca (against tree direction)
1512 // If increase_on_entering, flow decreases in arcs pointing towards v
1513 p = v;
1514 while (p != lca)
1515 {
1516 Arc *pa = parent_arc(p);
1518 // from_parent=true means arc goes parent→child (towards v)
1519 // Since we go against tree direction, flow decreases when from_parent=true
1521
1523 bool goes_lower;
1524
1525 if (flow_increases)
1526 {
1527 slack = pa->cap - pa->flow;
1528 goes_lower = false;
1529 }
1530 else
1531 {
1532 slack = pa->flow;
1533 goes_lower = true;
1534 }
1535
1536 if (slack < delta or (slack == delta and goes_lower and not leaving_goes_lower))
1537 {
1538 delta = slack;
1539 leaving = pa;
1541 }
1542
1543 p = parent(p);
1544 }
1545
1546 // Allow degenerate pivots (delta=0) if we found a valid leaving arc
1547 // This restructures the tree without changing flow, potentially enabling
1548 // future pivots that were previously blocked.
1549 if (delta >= 0 and leaving != nullptr)
1550 {
1551 // Update entering arc
1553 entering->flow += delta;
1554 else
1555 entering->flow -= delta;
1556
1557 // Update u-side (same logic as above)
1558 p = u;
1559 while (p != lca)
1560 {
1561 Arc *pa = parent_arc(p);
1564
1565 if (flow_increases)
1566 pa->flow += delta;
1567 else
1568 pa->flow -= delta;
1569
1570 p = parent(p);
1571 }
1572
1573 // Update v-side (same logic as above)
1574 p = v;
1575 while (p != lca)
1576 {
1577 Arc *pa = parent_arc(p);
1580
1581 if (flow_increases)
1582 pa->flow += delta;
1583 else
1584 pa->flow -= delta;
1585
1586 p = parent(p);
1587 }
1588
1589 return true; // Successful pivot (including degenerate with delta=0)
1590 }
1591
1592 return false; // Failed - no valid cycle found
1593 }
1594
1605 {
1606 // Handle degenerate pivot where entering = leaving
1607 if (entering == leaving)
1608 {
1609 auto &ai = ainfo(entering);
1610 ai.state = leaving_goes_lower ?
1612 return;
1613 }
1614
1615 // Set leaving arc state
1618
1619 // Set entering arc as tree arc
1621
1622 // Find which end of leaving arc becomes the new subtree root
1623 // One of the endpoints must have leaving as its parent_arc
1624 auto leaving_src = static_cast<Node *>(leaving->src_node);
1625 auto leaving_tgt = static_cast<Node *>(leaving->tgt_node);
1626
1630
1632 return; // Invalid pivot
1633
1634 if (src_has_leaving)
1636 else
1638
1639 auto entering_src = static_cast<Node *>(entering->src_node);
1640 auto entering_tgt = static_cast<Node *>(entering->tgt_node);
1641
1642 // Determine which end of entering arc is in the subtree
1644 {
1645 Node *p = entering_src;
1646 bool src_in = false;
1647 while (p != nullptr)
1648 {
1649 if (p == subtree_root)
1650 {
1651 src_in = true;
1652 break;
1653 }
1654 p = parent(p);
1655 }
1656
1657 if (src_in)
1658 {
1661 }
1662 else
1663 {
1666 }
1667 }
1668
1669 // Reverse path from subtree_root to in_subtree
1670 DynList<Node *> path;
1671 Node *p = in_subtree;
1672 while (p != subtree_root and p != nullptr)
1673 {
1674 path.insert(p); // Prepend
1675 p = parent(p);
1676 }
1677 if (p == subtree_root)
1678 path.insert(subtree_root);
1679 else
1680 return; // in_subtree not descendant of subtree_root
1681
1682 // Reverse parent relationships along the path
1683 // Path is: [subtree_root, X, Y, ..., in_subtree] (built by prepending)
1684 //
1685 // Original tree (parent pointers):
1686 // in_subtree --> Y --> X --> subtree_root --> (via leaving to rest of tree)
1687 // (each node's parent is to its right)
1688 //
1689 // After reversal (parent pointers):
1690 // subtree_root --> X --> Y --> in_subtree --> out_subtree --> ...
1691 // (each node's parent is to its right, but in_subtree connects via entering)
1692 //
1693 // For each pair (curr, next) in [subtree_root, X, Y, ...]:
1694 // - Original: next.parent = curr, so parent_arc(next) = arc between them
1695 // - New: curr.parent = next, using the same arc
1696 for (auto it = path.get_it(); it.has_curr(); )
1697 {
1698 Node *curr = it.get_curr();
1699 it.next();
1700
1701 if (not it.has_curr())
1702 break;
1703
1704 Node *next = it.get_curr();
1705
1706 // Original: next was child of curr, so parent_arc(next) = arc between curr and next
1708 auto &curr_info = ninfo(curr);
1709 curr_info.parent = next;
1710 curr_info.parent_arc = arc_between;
1711
1712 auto arc_src = static_cast<Node *>(arc_between->src_node);
1713 curr_info.arc_from_parent = (arc_src == next);
1714 }
1715
1716 // Link in_subtree to out_subtree via entering arc
1717 auto &sub_info = ninfo(in_subtree);
1718 sub_info.parent = out_subtree;
1719 sub_info.parent_arc = entering;
1720 sub_info.arc_from_parent = (static_cast<Node *>(entering->src_node) == out_subtree);
1721
1722 // Update depths and potentials using BFS from in_subtree
1724 queue.put(in_subtree);
1725
1726 auto &out_info = ninfo(out_subtree);
1727 sub_info.depth = out_info.depth + 1;
1728 if (sub_info.arc_from_parent)
1729 sub_info.potential = out_info.potential - entering->cost;
1730 else
1731 sub_info.potential = out_info.potential + entering->cost;
1732
1733 while (not queue.is_empty())
1734 {
1735 Node *curr = queue.get();
1736 const auto &curr_info = ninfo(curr);
1737
1738 // Find children of curr (nodes whose parent is curr)
1739 for (typename Net::Node_Iterator nit(net); nit.has_curr(); nit.next_ne())
1740 {
1741 Node *child = nit.get_curr();
1742 if (child == curr)
1743 continue;
1744
1745 if (parent(child) != curr)
1746 continue;
1747
1748 auto &ci = ninfo(child);
1749 ci.depth = curr_info.depth + 1;
1750
1751 Arc *pa = parent_arc(child);
1752 if (ci.arc_from_parent)
1753 ci.potential = curr_info.potential - pa->cost;
1754 else
1755 ci.potential = curr_info.potential + pa->cost;
1756
1757 queue.put(child);
1758 }
1759 }
1760 }
1761
1762 public:
1768
1784
1791 {
1792 return ainfo(a).lower_bound;
1793 }
1794
1801 {
1802 return std::abs(a->flow - ainfo(a).lower_bound) < eps();
1803 }
1804
1811 {
1812 return std::abs(a->flow - a->cap) < eps();
1813 }
1814
1821 {
1822 return a->cap - a->flow;
1823 }
1824
1831 {
1832 return a->flow - ainfo(a).lower_bound;
1833 }
1834
1835
1836 public:
1846 {
1848 << "Network is not single source and single sink";
1849
1850 stats.reset();
1851 auto total_start = std::chrono::high_resolution_clock::now();
1852
1855
1856 // Count initial partial-flow arcs
1858
1859 // PHASE I: Establish valid basic feasible solution
1860 auto phase1_start = std::chrono::high_resolution_clock::now();
1861 size_t phase1_pivots = force_partial_arcs_into_tree();
1862 auto phase1_end = std::chrono::high_resolution_clock::now();
1863 stats.phase1_time_ms = std::chrono::duration<double, std::milli>(
1864 phase1_end - phase1_start).count();
1865 stats.phase1_pivots = phase1_pivots;
1866 stats.forced_into_tree = phase1_pivots;
1867
1868 // PHASE II: Optimize cost using standard Network Simplex
1869 auto phase2_start = std::chrono::high_resolution_clock::now();
1870 num_pivots = phase1_pivots;
1871 size_t failed_attempts = 0;
1872 const size_t max_pivots = net.vsize() * net.esize() * 10 + 1000;
1873 const size_t max_failures = net.esize() + 1;
1874
1876 {
1877 Arc *entering = find_entering_arc();
1878
1879 if (entering == nullptr)
1880 break; // Optimal!
1881
1882 Flow_Type delta;
1883 Arc *leaving;
1884 bool leaving_goes_lower;
1885
1886 bool success = augment_and_find_leaving(entering, delta, leaving, leaving_goes_lower);
1887
1888 if (success)
1889 {
1890 if (std::abs(delta) < eps())
1892
1894 ++num_pivots;
1895 failed_attempts = 0;
1896
1897 // Reset skip flags after successful pivot
1898 for (typename Net::Arc_Iterator ait(net); ait.has_curr(); ait.next_ne())
1899 ainfo(ait.get_curr()).skip = false;
1900 }
1901 else
1902 {
1903 ainfo(entering).skip = true;
1905 }
1906 }
1907
1908 auto phase2_end = std::chrono::high_resolution_clock::now();
1909 stats.phase2_time_ms = std::chrono::duration<double, std::milli>(
1910 phase2_end - phase2_start).count();
1911 stats.phase2_pivots = num_pivots - phase1_pivots;
1912
1913 auto total_end = std::chrono::high_resolution_clock::now();
1914 stats.total_time_ms = std::chrono::duration<double, std::milli>(
1915 total_end - total_start).count();
1917
1918 // Count tree arcs
1919 stats.tree_arcs = 0;
1920 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1921 if (ainfo(it.get_curr()).state == Simplex_Arc_State::Tree)
1922 ++stats.tree_arcs;
1923
1924 return num_pivots;
1925 }
1926
1928 [[nodiscard]] size_t get_num_pivots() const { return num_pivots; }
1929
1932
1934 void print_stats() const
1935 {
1936 std::cout << "=== Network Simplex Statistics ===\n"
1937 << "Total pivots: " << stats.total_pivots << "\n"
1938 << " Phase I pivots: " << stats.phase1_pivots << "\n"
1939 << " Phase II pivots: " << stats.phase2_pivots << "\n"
1940 << " Degenerate pivots: " << stats.degenerate_pivots << "\n"
1941 << "Tree arcs: " << stats.tree_arcs << " (expected " << (net.vsize() - 1) << ")\n"
1942 << "Initial partial-flow arcs: " << stats.initial_partial_arcs << "\n"
1943 << "Arcs forced into tree: " << stats.forced_into_tree << "\n"
1944 << "Timing:\n"
1945 << " Phase I: " << stats.phase1_time_ms << " ms\n"
1946 << " Phase II: " << stats.phase2_time_ms << " ms\n"
1947 << " Total: " << stats.total_time_ms << " ms\n";
1948 }
1949
1963 {
1964 size_t forced_pivots = 0;
1965 bool made_progress = true;
1966
1967 while (made_progress)
1968 {
1969 made_progress = false;
1970
1971 // Find a non-tree arc with partial flow
1972 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1973 {
1974 auto a = it.get_curr();
1975 if (ainfo(a).state == Simplex_Arc_State::Tree)
1976 continue;
1977
1978 if (not is_partial_flow(a))
1979 continue;
1980
1981 // Found a partial-flow arc not in tree - force it in
1982 // Mark it as Lower (to increase flow direction)
1984
1985 Flow_Type delta;
1986 Arc *leaving;
1987 bool leaving_goes_lower;
1988
1989 // Try to find a valid cycle and leaving arc
1990 bool success = augment_and_find_leaving(a, delta, leaving, leaving_goes_lower);
1991
1992 if (success and leaving != nullptr and leaving != a)
1993 {
1994 // Verify leaving arc is in tree
1996 {
1998 continue;
1999 }
2000
2002 ++forced_pivots;
2003 made_progress = true;
2004 break;
2005 }
2006 else
2007 {
2008 // Try the other direction (Upper = decrease flow)
2011
2012 if (success and leaving != nullptr and leaving != a)
2013 {
2015 ++forced_pivots;
2016 made_progress = true;
2017 break;
2018 }
2019 else
2020 {
2021 // Cannot add this arc - restore to appropriate bound
2022 if (a->flow <= eps())
2024 else if (a->flow >= a->cap - eps())
2026 else
2027 ainfo(a).state = Simplex_Arc_State::Lower; // Should not happen
2028 }
2029 }
2030 }
2031 }
2032
2033 return forced_pivots;
2034 }
2035
2045 {
2046 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2047 {
2048 auto a = it.get_curr();
2049 if (ainfo(a).state == Simplex_Arc_State::Tree)
2050 continue;
2051
2052 // Non-tree arc must be at bounds
2053 if (is_partial_flow(a))
2054 return false;
2055 }
2056 return true;
2057 }
2058
2061 {
2062 size_t count = 0;
2063 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2064 {
2065 auto a = it.get_curr();
2067 ++count;
2068 }
2069 return count;
2070 }
2071
2080 {
2081 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2082 {
2083 auto a = it.get_curr();
2084 if (ainfo(a).state != Simplex_Arc_State::Tree)
2085 continue;
2086
2087 auto rc = reduced_cost(a);
2088 if (std::abs(rc) > eps() * 100) // Allow small tolerance
2089 return false;
2090 }
2091 return true;
2092 }
2093
2099 {
2100 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
2101 {
2102 auto p = it.get_curr();
2103 if (p == root)
2104 continue;
2105
2106 auto pa = parent_arc(p);
2107 if (pa == nullptr)
2108 return false;
2109
2110 if (ainfo(pa).state != Simplex_Arc_State::Tree)
2111 return false;
2112 }
2113 return true;
2114 }
2115
2118 {
2119 std::cout << "\n=== Network Simplex Diagnostics ===\n";
2120
2121 // Count arc types
2122 size_t tree_arcs = 0, lower_arcs = 0, upper_arcs = 0;
2123 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2124 {
2125 switch (ainfo(it.get_curr()).state)
2126 {
2127 case Simplex_Arc_State::Tree: ++tree_arcs; break;
2128 case Simplex_Arc_State::Lower: ++lower_arcs; break;
2129 case Simplex_Arc_State::Upper: ++upper_arcs; break;
2130 }
2131 }
2132
2133 std::cout << "Arcs: Tree=" << tree_arcs << " Lower=" << lower_arcs
2134 << " Upper=" << upper_arcs << " Total=" << net.esize() << "\n";
2135 std::cout << "Expected tree arcs: " << (net.vsize() - 1) << "\n";
2136
2137 // Verify tree reduced costs
2139 std::cout << "Tree arcs rc=0: " << (tree_rc_ok ? "YES" : "NO") << "\n";
2140
2141 // Check for optimality violations
2142 size_t violations = 0;
2143 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2144 {
2145 auto a = it.get_curr();
2146 auto state = ainfo(a).state;
2147 auto rc = reduced_cost(a);
2148
2149 if (state == Simplex_Arc_State::Lower)
2150 {
2151 // Lower: flow=0, can increase. Optimal if rc >= 0
2152 if (rc < -eps() and a->flow < a->cap - eps())
2153 {
2154 ++violations;
2155 std::cout << " VIOLATION: Lower arc with rc=" << rc
2156 << " flow=" << a->flow << "/" << a->cap << "\n";
2157 }
2158 }
2159 else if (state == Simplex_Arc_State::Upper)
2160 {
2161 // Upper: flow=cap, can decrease. Optimal if rc <= 0
2162 if (rc > eps() and a->flow > eps())
2163 {
2164 ++violations;
2165 std::cout << " VIOLATION: Upper arc with rc=" << rc
2166 << " flow=" << a->flow << "/" << a->cap << "\n";
2167 }
2168 }
2169 }
2170
2171 std::cout << "Optimality violations: " << violations << "\n";
2172 std::cout << "==================================\n";
2173 }
2174 };
2175
2176
2214 template <FlowNetwork Net,
2215 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
2217 {
2218 Max_Flow_Algo<Net>()(net); // First compute maximum flow
2220 return simplex.run();
2221 }
2222
2223
2232 template <FlowNetwork Net,
2233 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
2246
2247} // end namespace Aleph
2248
2249# endif // TPL_NETCOST_H
Bellman-Ford algorithm for single-source shortest paths.
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
C++20 concepts for the protocol shared by graph algorithms.
WeightedDigraph::Arc Arc
size_t size_t int32_t * out
Definition ca-c-api.h:120
Bellman-Ford algorithm for shortest paths with negative weights.
bool has_curr() const noexcept
Return true the iterator has an current arc.
Definition tpl_graph.H:1726
Dynamic queue of elements of generic type T based on single linked list.
T & put(const T &data)
The type of element.
T get()
Remove the oldest item of the queue.
bool is_empty() const noexcept
Return true if this is empty.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & insert(const T &item)
Definition htlist.H:1220
T & append(const T &item)
Definition htlist.H:1271
Generic key-value map implemented on top of a binary search tree.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair.
Data & find(const Key &key)
Find the value associated with key.
void empty()
remove all elements from the set
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Network Simplex algorithm for minimum cost flow.
Flow_Type residual_lower(Arc *a) const
Get residual lower (room to decrease flow).
const Arc_Info & ainfo(Arc *a) const
Get arc info const reference.
Arc * parent_arc(Node *p) const
Get parent arc.
Arc * find_entering_arc()
Find entering arc using most negative reduced cost.
size_t get_num_pivots() const
Return number of pivots performed in last run.
bool augment_and_find_leaving(Arc *entering, Flow_Type &delta, Arc *&leaving, bool &leaving_goes_lower)
Augment flow around the cycle and find leaving arc.
void pivot_tree(Arc *entering, Arc *leaving, bool leaving_goes_lower)
Update tree structure after pivot.
size_t run(Flow_Type unused=0)
Execute Network Simplex algorithm.
DynArray< Arc_Info > arc_info
Network_Simplex(Net &network)
Construct Network Simplex solver.
typename Net::Flow_Type Flow_Type
void set_lower_bound(Arc *a, Flow_Type lower_bound)
Set lower bound for an arc.
const Node_Info & ninfo(Node *p) const
Get node info const reference.
bool verify_tree_integrity() const
Verify tree integrity - all parent_arcs should be Tree arcs.
DynMapTree< Arc *, size_t > arc_to_idx
void build_spanning_tree()
Build initial spanning tree from source.
void init_structures()
Initialize data structures.
static Flow_Type eps()
Epsilon for floating-point comparisons.
Node * find_lca(Node *u, Node *v)
Find the lowest common ancestor of two nodes.
Flow_Type residual_capacity(Arc *a) const
Get residual capacity (room to increase flow).
DynArray< Node_Info > node_info
bool is_partial_flow(Arc *a) const
Check if arc has partial flow (strictly between bounds).
Flow_Type reduced_cost(Arc *a) const
Compute reduced cost of an arc.
size_t count_non_tree_partial_arcs() const
Count arcs with partial flow not in tree.
static constexpr Flow_Type Inf
Flow_Type get_lower_bound(Arc *a) const
Get lower bound for an arc.
bool is_at_lower_bound(Arc *a) const
Check if arc flow is at lower bound.
long depth(Node *p) const
Get depth.
NetworkSimplexStats stats
DynMapTree< Node *, size_t > node_to_idx
void print_stats() const
Print execution statistics to stdout.
typename Net::Node Node
bool is_valid_basic_solution() const
Check if current solution is a valid basic feasible solution.
bool is_at_upper_bound(Arc *a) const
Check if arc flow is at upper bound (capacity).
size_t force_partial_arcs_into_tree()
Phase I: Force all partial-flow arcs into the spanning tree.
void print_diagnostics() const
Print diagnostic information about current state.
Node * parent(Node *p) const
Get parent node.
Arc_Info & ainfo(Arc *a)
Get arc info reference.
Node_Info & ninfo(Node *p)
Get node info reference.
const NetworkSimplexStats & get_stats() const noexcept
Return execution statistics from last run.
Flow_Type potential(Node *p) const
Get potential.
typename Net::Arc Arc
bool verify_tree_reduced_costs() const
Verify that tree arcs have zero reduced cost.
bool is_zero(Flow_Type x) const
Check if value is effectively zero.
Filtered iterator for outcoming arcs of a node.
Definition tpl_graph.H:1831
Path on a graph.
Definition tpl_graph.H:2772
bool is_cycle() const
Return true if this is a cycle; throws if path is empty.
Definition tpl_graph.H:3270
bool is_empty() const noexcept
Return true if the path is empty.
Definition tpl_graph.H:2916
void for_each_arc(Operation op=Operation()) const
Execute an operation on each arc of path.
Definition tpl_graph.H:3452
Container< Arc * > arcs() const
Return a container with all the arcs of the graph.
Definition graph-dry.H:2844
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:820
constexpr size_t vsize() const noexcept
Definition graph-dry.H:746
size_t esize() const noexcept
Return the total of arcs of graph.
Definition graph-dry.H:840
Container< Node * > nodes() const
Return a container with all the nodes of the graph.
Definition graph-dry.H:2826
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
QuadTree - Hierarchical spatial index for 2D points.
Definition quadtree.H:126
Graph visualization and output generation utilities.
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
#define NODE_COUNTER(p)
Get the counter of a node.
Container< T > arcs_map(GT &g, Op transformation, SA sa=SA())
Map the filtered arcs of a graph to a transformed type.
Definition tpl_graph.H:1427
#define NODE_COOKIE(p)
Return the node cookie
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Net_Graph< Net_Node< string >, Net_Arc< Empty_Class, FlowType > > Net
double Flow_Type
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Itor lower_bound(Itor beg, Itor end, const T &value)
Find lower bound in a sorted range.
Definition ahAlgo.H:1190
DynList< typename Net::Arc * > get_partial_arcs(const Net &net)
Get arcs with partial flow (0 < flow < cap).
Residual_Net< typenameNet::Flow_Type >::Node * build_residual_net(const Net &net, Residual_Net< typename Net::Flow_Type > &rnet, DynMapTree< void *, void * > &arcs)
Build a residual network from a flow network.
void cancel_cycle(const Res_Net &, const Path< Res_Net > &path)
Cancel a negative cycle by augmenting flow.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip(const Container1 &a, const Container2 &b)
Zip two containers into a list of pairs.
and
Check uniqueness with explicit hash + equality functors.
void residual_to_net(const DynMapTree< void *, void * > &arcs)
Transfer flow values from residual network back to original.
std::tuple< size_t, double > max_flow_min_cost_by_cycle_canceling(Net &net, double it_factor=0.4, size_t step=10)
Compute maximum flow at minimum cost using cycle canceling.
void create_residual_arc(const Net &net, PP_Res_Net< Net > &rnet, typename Net::Arc *a)
Create residual arcs for a in the residual network.
Definition tpl_net.H:1393
size_t max_flow_min_cost_by_network_simplex(Net &net)
Compute maximum flow at minimum cost using Network Simplex.
Simplex_Arc_State
Arc state in Network Simplex.
@ Upper
Non-basic arc at upper bound (flow = cap).
@ Tree
Basic arc (in spanning tree).
@ Lower
Non-basic arc at lower bound (flow = 0).
std::tuple< DynList< typename Net::Arc * >, DynList< typename Net::Arc * >, DynList< typename Net::Arc * > > Feasible_Tree
Feasible spanning tree classification.
void print_net_cost(const Net &net, std::ostream &out)
Output a flow network to Graphviz format.
bool check_residual_net(const Res_Net &net)
Verify residual network consistency.
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
void print_residual_net(const Residual_Net< typename Net::Flow_Type > &net, std::ostream &out)
Output a residual network to Graphviz format.
Feasible_Tree< Net > build_feasible_spanning_tree(const Net &net)
Build feasible spanning tree classification.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1165
Iterator over arcs of a graph.
Definition tpl_agraph.H:325
Functor wrapper for ford_fulkerson_maximum_flow().
Definition tpl_net.H:1534
Functor wrapper for maximum flow minimum cost algorithm.
std::tuple< size_t, double > operator()(Net &net, const double it_factor=0.4, const size_t step=10)
Execute the algorithm.
Functor wrapper for Network Simplex algorithm.
size_t operator()(Net &net)
Execute the algorithm.
Arc of a flow network implemented with adjacency lists.
Definition tpl_net.H:115
Net_Arc & operator=(const Net_Arc &arc)
Copy assignment.
Definition tpl_net.H:148
Flow_Type flow
Flow value.
Definition tpl_net.H:124
Arc type for maximum flow minimum cost networks.
Definition tpl_netcost.H:95
Flow_Type cost
Cost per unit of flow (negative for residual arcs).
Flow_Type flow_cost() const noexcept
Return the cost of the current flow through this arc.
Net_Cost_Arc(const Net_Cost_Arc &a)
Copy constructor.
Net_Cost_Arc & operator=(const Net_Cost_Arc &a)
Copy assignment operator.
Net_Cost_Arc()=default
Default constructor.
F_Type Flow_Type
Type representing flow, capacity, and cost values.
Capacitated flow network with costs associated to arcs.
typename Arc::Arc_Type Arc_Type
Type of attribute stored in an arc.
Flow_Type flow_cost() const
Compute the total cost of flow circulating through the network.
Flow_Type get_cost(Arc *a) const noexcept
Return the cost of an arc (const version).
typename Node::Node_Type Node_Type
Type of attribute stored in a node.
auto in_pars(Node *p)
Compute incoming flow parameters for a node.
Net_Cost_Graph & operator=(const Net_Cost_Graph &net)
Copy assignment operator (uses copy-and-swap idiom).
typename Arc::Flow_Type Flow_Type
Type representing capacity, flow, and cost values.
Net_Cost_Graph(Net_Cost_Graph &&)=default
Move constructor.
auto out_pars(Node *p)
Compute outgoing flow parameters for a node.
NodeT Node
Node type.
Net_Cost_Graph()=default
Default constructor.
virtual Arc * insert_arc(Node *src_node, Node *tgt_node)
Insert arc (internal use only).
Net_Cost_Graph(const Net_Cost_Graph &net)
Copy constructor.
Flow_Type & get_cost(Arc *a) noexcept
Return a modifiable reference to the cost of an arc.
Arc * emplace_arc(Node *src_node, Node *tgt_node, const Flow_Type &cap, const Flow_Type &__cost, Args &&... args)
Create and insert an arc with arc info using perfect forwarding.
virtual Arc * insert_arc(Node *src_node, Node *tgt_node, const Flow_Type &cap, const Flow_Type &__cost)
Create and insert an arc in a flow network with costs.
static Flow_Type arc_flow_cost(Arc *a) noexcept
Compute the cost of the flow through an arc.
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
constexpr bool is_single_source() const noexcept
Return true if the network has a single source.
Definition tpl_net.H:369
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
ArcT Arc
Arc type.
Definition tpl_net.H:272
typename Arc::Flow_Type Flow_Type
Capacity/flow numeric type.
Definition tpl_net.H:278
constexpr bool is_single_sink() const noexcept
Return true if the network has a single sink.
Definition tpl_net.H:372
NodeT Node
Node type.
Definition tpl_net.H:275
void swap(Net_Graph &other) noexcept
Swap contents with another network. O(1) operation.
Definition tpl_net.H:731
Execution statistics for Network Simplex algorithm.
double phase1_time_ms
Phase I elapsed time in milliseconds.
size_t tree_arcs
Number of arcs in spanning tree.
size_t degenerate_pivots
Pivots with zero flow change.
size_t total_pivots
Total pivot operations.
size_t initial_partial_arcs
Arcs with partial flow before Phase I.
size_t phase1_pivots
Pivots in Phase I (feasibility)
size_t phase2_pivots
Pivots in Phase II (optimization)
size_t forced_into_tree
Arcs forced into tree in Phase I.
double total_time_ms
Total elapsed time in milliseconds.
double phase2_time_ms
Phase II elapsed time in milliseconds.
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1120
Cost distance functor for Bellman-Ford on residual networks.
Rcost() noexcept=default
static void set_zero(typename Net::Arc *a) noexcept
Reset arc to zero state.
typename Net::Flow_Type Distance_Type
Residual arc type with mirror pointer.
Res_Arc * img
Pointer to the mirror arc in the opposite direction.
bool is_residual
True if this is a residual (backward) arc.
Arc filter for residual networks.
Res_Filt() noexcept=default
Default constructor.
Res_Filt(typename Net::Node *) noexcept
Constructor (node parameter ignored).
Arc information for Network Simplex algorithm.
bool skip
Skip this arc temporarily (failed pivot, will retry later).
Simplex_Arc_State state
Arc state (Lower, Upper, or Tree).
Ftype lower_bound
Lower bound on flow (default 0).
Node information for Network Simplex algorithm.
void * parent
Parent node in the spanning tree (nullptr for root).
bool arc_from_parent
True if parent_arc is oriented from parent towards this node.
long depth
Depth in the spanning tree (root has depth 0).
long mark
Mark used for LCA computation.
void * parent_arc
Arc connecting this node to its parent.
Ftype potential
Node potential (dual variable pi).
Functor class for generating Graphviz DOT specifications.
Articulation points (cut nodes), bridges, and biconnected components.
Dynamic key-value map based on balanced binary search trees.
Path finding algorithms in graphs.
Network flow graph structures.