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 <limits>
52# include <chrono>
53# include <tpl_net.H>
54# include <tpl_dynMapTree.H>
55# include <tpl_find_path.H>
56# include <tpl_cut_nodes.H>
57# include <Bellman_Ford.H>
58# include <generate_graph.H>
59# include <ah-errors.H>
60
61namespace Aleph
62{
70 template <typename Node_Info = Empty_Class>
72
73
91 template <typename Arc_Info = Empty_Class, typename F_Type = double>
92 struct Net_Cost_Arc : public Net_Arc<Arc_Info, F_Type>
93 {
95 using Base::Base;
96
99
102
104 Net_Cost_Arc() = default;
105
108 : Base(a), cost(a.cost)
109 { /* empty */
110 }
111
114 {
115 if (&a == this)
116 return *this;
118 cost = a.cost;
119 return *this;
120 }
121
124 };
125
126
144 template <class NodeT = Net_Cost_Node<Empty_Class>,
145 class ArcT = Net_Cost_Arc<Empty_Class, double>>
146 struct Net_Cost_Graph : public Net_Graph<NodeT, ArcT>
147 {
149
152
155
157 using Arc = ArcT;
158
160 using Node = NodeT;
161
163 using Flow_Type = typename Arc::Flow_Type;
164
166 using Node_Type = typename Node::Node_Type;
167
169 using Arc_Type = typename Arc::Arc_Type;
170
172 Net_Cost_Graph() = default;
173
182 {
183 zip(this->arcs(), net.arcs()).for_each([](const auto & p)
184 {
185 auto atgt = p.first;
186 auto asrc = p.second;
187 atgt->cost = asrc->cost;
188 });
189 }
190
193
196 {
197 if (this == &net)
198 return *this;
199 Net_Cost_Graph tmp(net); // copy construct (copies capacity, flow, and cost)
200 this->swap(tmp); // swap with copy
201 return *this;
202 }
203
206
212 Flow_Type &get_cost(Arc *a) noexcept { return a->cost; }
213
219 Flow_Type get_cost(Arc *a) const noexcept { return a->cost; }
220
226 static Flow_Type arc_flow_cost(Arc *a) noexcept { return a->flow_cost(); }
227
239 virtual Arc * insert_arc(Node *src_node, Node *tgt_node,
240 const Flow_Type & cap, const Flow_Type & __cost)
241 {
242 Arc *a = Net::insert_arc(src_node, tgt_node, cap, 0, Arc_Type());
243 a->cost = __cost;
244 return a;
245 }
246
257 template <typename... Args>
258 Arc * emplace_arc(Node *src_node, Node *tgt_node,
259 const Flow_Type & cap, const Flow_Type & __cost,
260 Args &&... args)
261 {
262 auto a = Net::insert_arc(src_node, tgt_node, cap, 0,
263 Arc_Type(std::forward<Args>(args)...));
264 a->cost = __cost;
265 return a;
266 }
267
277 virtual Arc * insert_arc(Node *src_node, Node *tgt_node)
278 {
279 Arc *a = Net::insert_arc(src_node, tgt_node, Arc_Type());
280 a->cost = 0;
281 return a;
282 }
283
291 {
292 Flow_Type total = 0;
293 for (Arc_Iterator<Net_MFMC> it(*this); it.has_curr(); it.next_ne())
294 {
295 Arc *a = it.get_curr();
296 total += a->flow_cost();
297 }
298 return total;
299 }
300
307 auto out_pars(Node *p)
308 {
309 Flow_Type cap_sum = 0, flow_sum = 0, cost_sum = 0;
310 for (_Out_Iterator<Net> it(p); it.has_curr(); it.next_ne())
311 {
312 Arc *a = it.get_curr();
313 cap_sum += a->cap;
314 flow_sum += a->flow;
315 cost_sum += a->cost;
316 }
317 return std::make_tuple(cap_sum, flow_sum, cost_sum);
318 }
319
326 auto in_pars(Node *p)
327 {
328 Flow_Type cap_sum = 0, flow_sum = 0, cost_sum = 0;
329 for (_In_Iterator<Net> it(p); it.has_curr(); it.next_ne())
330 {
331 Arc *a = it.get_curr();
332 cap_sum += a->cap;
333 flow_sum += a->flow;
334 cost_sum += a->cost;
335 }
336 return std::make_tuple(cap_sum, flow_sum, cost_sum);
337 }
338 };
339
340
348 template <class Net>
349 struct Res_Filt
350 {
352 Res_Filt(typename Net::Node *) noexcept {}
353
356
363 {
364 return a->cap > a->flow;
365 }
366 };
367
368
377 template <class Net>
378 struct Rcost
379 {
381
383
390 {
391 return a->cost;
392 }
393
400 static void set_zero(typename Net::Arc *a) noexcept
401 {
402 a->cap = std::numeric_limits<Distance_Type>::max();
403 a->flow = 0;
404 a->cost = 0;
405 }
406 };
407
408
417 template <typename Ftype>
418 struct Res_Arc : public Net_Cost_Arc<Empty_Class, Ftype>
419 {
421 using Base::Base;
422
424 bool is_residual = false;
425
427 Res_Arc *img = nullptr;
428 };
429
430
436 template <typename Ftype>
438
439
458 template <class Res_Net>
459 typename Res_Net::Arc *
461 typename Res_Net::Node *src,
462 typename Res_Net::Node *tgt,
463 const typename Res_Net::Flow_Type cap,
464 const typename Res_Net::Flow_Type flow,
465 const typename Res_Net::Flow_Type cost)
466 {
468
469 auto arc = residual_net.insert_arc(src, tgt, cap, cost);
470 auto rarc = residual_net.insert_arc(tgt, src, cap, -cost);
471
472 arc->is_residual = false;
473 arc->flow = flow;
474 arc->img = rarc;
475
476 rarc->is_residual = true;
477 rarc->img = arc;
478 rarc->flow = arc->cap - arc->flow;
479
480 assert(arc->cap == cap and arc->flow == flow and arc->cost == cost);
481 assert(rarc->cap == cap and rarc->flow == cap - flow and rarc->cost == -cost);
482
483 return arc;
484 }
485
486
502 template <class Net>
507 {
509 << "Network is not single source and single sink";
510
512
513 // Copy nodes from net to residual network
514 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
515 {
516 auto p = it.get_curr();
517 auto q = rnet.insert_node();
519 }
520
521 // Create residual arcs and build mapping
522 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
523 {
524 auto ga = it.get_curr();
525 auto gsrc = static_cast<typename Net::Node *>(ga->src_node);
526 auto gtgt = static_cast<typename Net::Node *>(ga->tgt_node);
527
531 ga->cap, ga->flow, ga->cost);
532 arcs.insert(ga, ra);
533 }
534
536
537 return static_cast<typename Rnet::Node *>(NODE_COOKIE(net.get_source()));
538 }
539
540
550 template <class Res_Net>
551 bool check_residual_net(const Res_Net & net)
552 {
553 return net.all_arcs([](typename Res_Net::Arc *a)
554 {
555 return a->img != nullptr and a->img->img == a;
556 });
557 }
558
559
572 template <class Res_Net>
573 void cancel_cycle(const Res_Net &, const Path<Res_Net> & path)
574 {
576 << "Path is empty or not a cycle";
577
578 using Ftype = typename Res_Net::Flow_Type;
579
580 // Determine minimum slack (bottleneck capacity) of the cycle
581 Ftype slack = std::numeric_limits<Ftype>::max();
582 path.for_each_arc([&slack](typename Res_Net::Arc *a)
583 {
584 assert(a->cap - a->flow > 0);
585 slack = std::min(slack, a->cap - a->flow);
586 });
587
588 // Cancel the cycle by augmenting flow
589 path.for_each_arc([slack](typename Res_Net::Arc *a)
590 {
591 auto img = a->img;
592 assert(img->img == a);
593 assert(a->cap == img->cap);
594 a->flow += slack;
595 img->flow -= slack;
596 });
597 }
598
599
609 template <class Net>
611 {
613 arcs.for_each([](std::pair<void *, void *> p)
614 {
615 auto net_arc = static_cast<typename Net::Arc *>(p.first);
616 auto res_arc = static_cast<typename Rnet::Arc *>(p.second);
617 net_arc->flow = res_arc->flow;
618 });
619 }
620
621
665 template <class Net,
666 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
667 std::tuple<size_t, double>
669 double it_factor = 0.4,
670 size_t step = 10)
671 {
672 Max_Flow_Algo<Net>()(net); // First compute maximum flow
673
677
678 // Build residual network
679 Rnet rnet;
681 typename Rnet::Node *source = build_residual_net(net, rnet, arcs_map);
682
683 size_t count = 0;
684 bool found_cycle = true;
685
686 // Main loop: find and cancel negative cycles
687 while (found_cycle)
688 {
689 // Search for negative cycle from source
690 auto [cycle, iterations] =
691 BF(rnet).search_negative_cycle(source, it_factor, step);
692
693 if (cycle.is_empty())
694 {
695 // No cycle found from source, try global search
696 auto [global_cycle, global_iter] =
697 BF(rnet).search_negative_cycle(it_factor, step);
698
700 found_cycle = false;
701 else
702 {
704 ++count;
705 }
706 }
707 else
708 { // Update iteration factor based on when cycle was found
709 it_factor = static_cast<double>(iterations) / net.vsize();
711 ++count;
712 }
713 }
714
715 // Transfer results back to original network
717
718 return std::make_tuple(count, it_factor);
719 }
720
721
732 template <class Net,
733 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
735 {
743 std::tuple<size_t, double> operator ()(Net & net,
744 const double it_factor = 0.4,
745 const size_t step = 10)
746 {
748 (net, it_factor, step);
749 }
750 };
751
752
763 template <class Net>
764 void print_net_cost(const Net & net, std::ostream & out)
765 {
766 long i = 0;
767 net.nodes().for_each([&i](typename Net::Node *p)
768 {
769 NODE_COUNTER(p) = i++;
770 });
771
772 struct Show_Node
773 {
774 void operator ()(const Net &, typename Net::Node *p, std::ostream & o)
775 {
776 o << "label = \"(" << p->get_info() << "," << NODE_COUNTER(p) << ")\"";
777 }
778 };
779
780 struct Show_Arc
781 {
782 void operator ()(const Net &, typename Net::Arc *a, std::ostream & o)
783 {
784 o << "label = \"" << a->flow << "/" << a->cap << "/" << a->cost << "\"";
785 }
786 };
787
789 }
790
791
801 template <class Net>
803 std::ostream & out)
804 {
806
807 long i = 0;
808 net.nodes().for_each([&i](typename Rnet::Node *p)
809 {
810 NODE_COUNTER(p) = i++;
811 });
812
813 struct Show_Node
814 {
815 void operator ()(const Rnet &, typename Rnet::Node *p, std::ostream & o)
816 {
817 o << "label = \"" << NODE_COUNTER(p) << "\"";
818 }
819 };
820
821 struct Show_Arc
822 {
823 void operator ()(const Rnet &, typename Rnet::Arc *a, std::ostream & o)
824 {
825 o << "label = \"" << a->flow << "/" << a->cap << "/" << a->cost << "\"";
826 if (a->is_residual)
827 o << " color = red";
828 }
829 };
830
832 Res_Filt<Rnet>>().digraph(net, out);
833 }
834
835
836 // =========================================================================
837 // Network Simplex Algorithm Implementation
838 // =========================================================================
839
850 template <class Net>
851 using Feasible_Tree = std::tuple<DynList<typename Net::Arc *>,
854
855
865 template <class Net>
867 {
868 using Arc = typename Net::Arc;
869 DynList<Arc *> empty, full, partial;
870
871 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
872 {
873 if (auto a = it.get_curr(); a->flow == 0)
874 empty.append(a);
875 else if (a->flow == a->cap)
876 full.append(a);
877 else
878 partial.append(a);
879 }
880
881 return std::make_tuple(std::move(empty), std::move(full), std::move(partial));
882 }
883
884
892 template <class Net>
894 {
896 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
897 if (auto a = it.get_curr(); a->flow > 0 and a->flow < a->cap)
898 ret.append(a);
899 return ret;
900 }
901
902
912 template <typename Ftype>
914 {
917
919 void *parent = nullptr;
920
922 void *parent_arc = nullptr;
923
925 long depth = 0;
926
928 bool arc_from_parent = true;
929
931 long mark = 0;
932 };
933
934
940 enum class Simplex_Arc_State : unsigned char
941 {
942 Lower,
943 Upper,
944 Tree
945 };
946
947
953 template <typename Ftype>
963
964
971 {
972 size_t total_pivots = 0;
973 size_t phase1_pivots = 0;
974 size_t phase2_pivots = 0;
975 size_t degenerate_pivots = 0;
976 size_t tree_arcs = 0;
977 double phase1_time_ms = 0.0;
978 double phase2_time_ms = 0.0;
979 double total_time_ms = 0.0;
981 size_t forced_into_tree = 0;
982
984 {
985 total_pivots = 0;
986 phase1_pivots = 0;
987 phase2_pivots = 0;
989 tree_arcs = 0;
990 phase1_time_ms = 0.0;
991 phase2_time_ms = 0.0;
992 total_time_ms = 0.0;
995 }
996 };
997
998
1039 template <class Net>
1041 {
1042 public:
1043 using Node = typename Net::Node;
1044 using Arc = typename Net::Arc;
1045 using Flow_Type = typename Net::Flow_Type;
1048
1049 private:
1055 Node *root = nullptr;
1056 size_t num_pivots = 0;
1057 long lca_mark = 0; // Counter for LCA marking
1060
1061 static constexpr Flow_Type Inf = std::numeric_limits<Flow_Type>::max();
1062
1065 {
1066 if constexpr (std::is_floating_point_v<Flow_Type>)
1067 return std::numeric_limits<Flow_Type>::epsilon() * 1000;
1068 else
1069 return 0;
1070 }
1071
1074
1076 const Node_Info &ninfo(Node *p) const { return node_info(node_to_idx.find(p)); }
1077
1080
1082 const Arc_Info &ainfo(Arc *a) const { return arc_info(arc_to_idx.find(a)); }
1083
1085 Node *parent(Node *p) const { return static_cast<Node *>(ninfo(p).parent); }
1086
1088 Arc *parent_arc(Node *p) const { return static_cast<Arc *>(ninfo(p).parent_arc); }
1089
1091 long depth(Node *p) const { return ninfo(p).depth; }
1092
1094 Flow_Type potential(Node *p) const { return ninfo(p).potential; }
1095
1097 bool is_zero(Flow_Type x) const
1098 {
1099 if constexpr (std::is_floating_point_v<Flow_Type>)
1100 return std::abs(x) <= eps();
1101 else
1102 return x == 0;
1103 }
1104
1110 {
1111 auto src = static_cast<Node *>(a->src_node);
1112 auto tgt = static_cast<Node *>(a->tgt_node);
1113 return a->cost - ninfo(src).potential + ninfo(tgt).potential;
1114 }
1115
1118 {
1119 node_info.cut(0);
1120 arc_info.cut(0);
1122 arc_to_idx.empty();
1123
1124 // Map nodes to indices
1125 size_t idx = 0;
1126 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
1127 {
1128 auto p = it.get_curr();
1129 node_to_idx.insert(p, idx);
1130 node_info.touch(idx) = Node_Info{};
1131 ++idx;
1132 }
1133
1134 // Map arcs to indices - DO NOT classify yet, let build_spanning_tree handle it
1135 idx = 0;
1136 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1137 {
1138 auto a = it.get_curr();
1139 arc_to_idx.insert(a, idx);
1140 arc_info.touch(idx) = Arc_Info{};
1141 // Initially mark all arcs as Lower; build_spanning_tree will fix this
1143 ++idx;
1144 }
1145 }
1146
1148 bool is_partial_flow(Arc *a) const
1149 {
1150 return a->flow > eps() and a->flow < a->cap - eps();
1151 }
1152
1162 {
1163 root = net.get_source();
1164
1165 // Reset all nodes
1166 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
1167 {
1168 auto p = it.get_curr();
1169 auto &ni = ninfo(p);
1170 ni.parent = nullptr;
1171 ni.parent_arc = nullptr;
1172 ni.depth = -1;
1173 ni.potential = 0;
1174 ni.mark = 0;
1175 }
1176
1177 // Reset all arcs to Lower
1178 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1179 ainfo(it.get_curr()).state = Simplex_Arc_State::Lower;
1180
1181 const size_t total_nodes = net.vsize();
1183 queue.put(root);
1184 ninfo(root).depth = 0;
1185 ninfo(root).potential = 0;
1186
1187 size_t nodes_in_tree = 1;
1188
1189 // Helper to add a node to tree via an arc
1190 auto add_to_tree = [&](Node *p, Arc *a, Node *other) -> bool {
1191 if (ninfo(other).depth >= 0)
1192 return false; // Already in tree
1193
1194 const auto &pi = ninfo(p);
1195 auto &oi = ninfo(other);
1196 oi.parent = p;
1197 oi.parent_arc = a;
1198 oi.depth = pi.depth + 1;
1199
1200 auto src = static_cast<Node *>(a->src_node);
1201 if (src == p)
1202 {
1203 oi.arc_from_parent = true;
1204 oi.potential = pi.potential - a->cost;
1205 }
1206 else
1207 {
1208 oi.arc_from_parent = false;
1209 oi.potential = pi.potential + a->cost;
1210 }
1211
1213 ++nodes_in_tree;
1214 queue.put(other);
1215 return true;
1216 };
1217
1218 // Build tree with multiple priority passes
1219 while (not queue.is_empty() and nodes_in_tree < total_nodes)
1220 {
1221 auto p = queue.get();
1222
1223 // Collect all candidate arcs with priorities
1224 struct ArcPriority {
1225 Arc* arc;
1226 Node* other;
1227 int priority; // 0 = partial flow, 1 = with flow, 2 = no flow
1228 };
1230
1231 for (Node_Arc_Iterator<Net> it(p); it.has_curr(); it.next_ne())
1232 {
1233 auto a = it.get_curr();
1234 auto other = net.get_connected_node(a, p);
1235 if (ninfo(other).depth >= 0)
1236 continue; // Already in tree
1237
1238 int prio;
1239 if (is_partial_flow(a))
1240 prio = 0; // Highest priority
1241 else if (a->flow > eps())
1242 prio = 1; // Medium priority
1243 else
1244 prio = 2; // Lowest priority
1245
1247 }
1248
1249 // Sort by priority (partial flow first)
1250 // Since DynList doesn't have sort, process in order
1251 for (int target_prio = 0; target_prio <= 2; ++target_prio)
1252 {
1253 for (auto& ap : candidates)
1254 {
1255 if (ap.priority == target_prio)
1256 add_to_tree(p, ap.arc, ap.other);
1257 }
1258 }
1259 }
1260
1261 // Classify remaining non-tree arcs
1262 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1263 {
1264 auto a = it.get_curr();
1265 if (ainfo(a).state == Simplex_Arc_State::Tree)
1266 continue;
1267
1268 if (a->flow <= eps())
1270 else if (a->flow >= a->cap - eps())
1272 else
1273 {
1274 // Partial flow arc NOT in tree - classify based on reduced cost
1275 auto rc = reduced_cost(a);
1276 ainfo(a).state = (rc < -eps()) ?
1278 }
1279 }
1280 }
1281
1299 {
1300 Arc *best = nullptr;
1301 Flow_Type best_violation = eps(); // Threshold to avoid tiny violations
1302 bool best_is_increase = true;
1303
1304 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1305 {
1306 auto a = it.get_curr();
1307 auto &ai = ainfo(a);
1308
1309 if (ai.state == Simplex_Arc_State::Tree)
1310 continue;
1311
1312 if (ai.skip) // Skip arcs that failed in this round
1313 continue;
1314
1315 const auto rc = reduced_cost(a);
1316 const bool can_increase = (a->flow < a->cap - eps());
1317 const bool can_decrease = (a->flow > eps());
1318
1319 // Check FORWARD direction: increase flow (rc < 0 is good)
1321 {
1322 best_violation = -rc;
1323 best = a;
1324 best_is_increase = true;
1325 }
1326
1327 // Check BACKWARD direction: decrease flow (rc > 0 is good)
1328 // This is equivalent to using the "reverse arc" in residual network
1330 {
1332 best = a;
1333 best_is_increase = false;
1334 }
1335 }
1336
1337 // Update state based on direction
1338 if (best != nullptr)
1339 {
1342 }
1343
1344 return best;
1345 }
1346
1356 {
1357 ++lca_mark; // Use new mark
1358
1359 // Mark path from u to root
1360 Node *p = u;
1361 while (p != nullptr)
1362 {
1363 ninfo(p).mark = lca_mark;
1364 p = parent(p);
1365 }
1366
1367 // Walk from v towards root until we hit a marked node
1368 p = v;
1369 while (p != nullptr and ninfo(p).mark != lca_mark)
1370 p = parent(p);
1371
1372 return p;
1373 }
1374
1396 {
1397 auto u = static_cast<Node *>(entering->src_node);
1398 auto v = static_cast<Node *>(entering->tgt_node);
1399 Node *lca = find_lca(u, v);
1400
1401 assert(lca != nullptr);
1402
1403 // Determine if we're increasing or decreasing flow on entering arc
1405
1406 // Count arcs in the cycle and check if it's a valid cycle
1407 // A valid cycle must have at least one arc where flow increases
1408 // and at least one where flow decreases (in the cycle direction)
1409 size_t arcs_with_increase = 0;
1410 size_t arcs_with_decrease = 0;
1411 size_t total_cycle_arcs = 1; // Start with entering arc
1412
1415 else
1417
1418
1419 // Walk from u to lca and count
1420 Node *p = u;
1421 while (p != lca)
1422 {
1425
1426 if (flow_increases)
1428 else
1430
1432 p = parent(p);
1433 }
1434
1435 // Walk from v to lca and count
1436 p = v;
1437 while (p != lca)
1438 {
1441
1442 if (flow_increases)
1444 else
1446
1448 p = parent(p);
1449 }
1450
1451 // If the cycle only has one arc (the entering arc itself) or
1452 // all arcs go in the same direction, it's not a valid cycle
1453 // for flow redistribution
1455 {
1456 delta = 0;
1457 leaving = entering;
1459 return false; // No valid pivot possible
1460 }
1461
1462 // Initialize with entering arc's slack
1464 delta = entering->cap - entering->flow;
1465 else
1466 delta = entering->flow;
1467
1468 leaving = entering;
1470
1471 // Walk from u to lca
1472 // Direction: lca → ... → u (following tree direction)
1473 // If increase_on_entering, flow increases in arcs pointing towards u
1474 p = u;
1475 while (p != lca)
1476 {
1477 Arc *pa = parent_arc(p);
1479 // from_parent=true means arc goes parent→child (towards u)
1480 // So flow increases when both are true or both are false
1482
1484 bool goes_lower;
1485
1486 if (flow_increases)
1487 {
1488 slack = pa->cap - pa->flow;
1489 goes_lower = false;
1490 }
1491 else
1492 {
1493 slack = pa->flow;
1494 goes_lower = true;
1495 }
1496
1497 // Prefer arc that goes to lower bound in case of tie (Bland's rule variant)
1498 if (slack < delta or (slack == delta and goes_lower and not leaving_goes_lower))
1499 {
1500 delta = slack;
1501 leaving = pa;
1503 }
1504
1505 p = parent(p);
1506 }
1507
1508 // Walk from v to lca
1509 // Direction: v → ... → lca (against tree direction)
1510 // If increase_on_entering, flow decreases in arcs pointing towards v
1511 p = v;
1512 while (p != lca)
1513 {
1514 Arc *pa = parent_arc(p);
1516 // from_parent=true means arc goes parent→child (towards v)
1517 // Since we go against tree direction, flow decreases when from_parent=true
1519
1521 bool goes_lower;
1522
1523 if (flow_increases)
1524 {
1525 slack = pa->cap - pa->flow;
1526 goes_lower = false;
1527 }
1528 else
1529 {
1530 slack = pa->flow;
1531 goes_lower = true;
1532 }
1533
1534 if (slack < delta or (slack == delta and goes_lower and not leaving_goes_lower))
1535 {
1536 delta = slack;
1537 leaving = pa;
1539 }
1540
1541 p = parent(p);
1542 }
1543
1544 // Allow degenerate pivots (delta=0) if we found a valid leaving arc
1545 // This restructures the tree without changing flow, potentially enabling
1546 // future pivots that were previously blocked.
1547 if (delta >= 0 and leaving != nullptr)
1548 {
1549 // Update entering arc
1551 entering->flow += delta;
1552 else
1553 entering->flow -= delta;
1554
1555 // Update u-side (same logic as above)
1556 p = u;
1557 while (p != lca)
1558 {
1559 Arc *pa = parent_arc(p);
1562
1563 if (flow_increases)
1564 pa->flow += delta;
1565 else
1566 pa->flow -= delta;
1567
1568 p = parent(p);
1569 }
1570
1571 // Update v-side (same logic as above)
1572 p = v;
1573 while (p != lca)
1574 {
1575 Arc *pa = parent_arc(p);
1578
1579 if (flow_increases)
1580 pa->flow += delta;
1581 else
1582 pa->flow -= delta;
1583
1584 p = parent(p);
1585 }
1586
1587 return true; // Successful pivot (including degenerate with delta=0)
1588 }
1589
1590 return false; // Failed - no valid cycle found
1591 }
1592
1603 {
1604 // Handle degenerate pivot where entering = leaving
1605 if (entering == leaving)
1606 {
1607 auto &ai = ainfo(entering);
1608 ai.state = leaving_goes_lower ?
1610 return;
1611 }
1612
1613 // Set leaving arc state
1616
1617 // Set entering arc as tree arc
1619
1620 // Find which end of leaving arc becomes the new subtree root
1621 // One of the endpoints must have leaving as its parent_arc
1622 auto leaving_src = static_cast<Node *>(leaving->src_node);
1623 auto leaving_tgt = static_cast<Node *>(leaving->tgt_node);
1624
1628
1630 return; // Invalid pivot
1631
1632 if (src_has_leaving)
1634 else
1636
1637 auto entering_src = static_cast<Node *>(entering->src_node);
1638 auto entering_tgt = static_cast<Node *>(entering->tgt_node);
1639
1640 // Determine which end of entering arc is in the subtree
1642 {
1643 Node *p = entering_src;
1644 bool src_in = false;
1645 while (p != nullptr)
1646 {
1647 if (p == subtree_root)
1648 {
1649 src_in = true;
1650 break;
1651 }
1652 p = parent(p);
1653 }
1654
1655 if (src_in)
1656 {
1659 }
1660 else
1661 {
1664 }
1665 }
1666
1667 // Reverse path from subtree_root to in_subtree
1668 DynList<Node *> path;
1669 Node *p = in_subtree;
1670 while (p != subtree_root and p != nullptr)
1671 {
1672 path.insert(p); // Prepend
1673 p = parent(p);
1674 }
1675 if (p == subtree_root)
1676 path.insert(subtree_root);
1677 else
1678 return; // in_subtree not descendant of subtree_root
1679
1680 // Reverse parent relationships along the path
1681 // Path is: [subtree_root, X, Y, ..., in_subtree] (built by prepending)
1682 //
1683 // Original tree (parent pointers):
1684 // in_subtree --> Y --> X --> subtree_root --> (via leaving to rest of tree)
1685 // (each node's parent is to its right)
1686 //
1687 // After reversal (parent pointers):
1688 // subtree_root --> X --> Y --> in_subtree --> out_subtree --> ...
1689 // (each node's parent is to its right, but in_subtree connects via entering)
1690 //
1691 // For each pair (curr, next) in [subtree_root, X, Y, ...]:
1692 // - Original: next.parent = curr, so parent_arc(next) = arc between them
1693 // - New: curr.parent = next, using the same arc
1694 for (auto it = path.get_it(); it.has_curr(); )
1695 {
1696 Node *curr = it.get_curr();
1697 it.next();
1698
1699 if (not it.has_curr())
1700 break;
1701
1702 Node *next = it.get_curr();
1703
1704 // Original: next was child of curr, so parent_arc(next) = arc between curr and next
1706 auto &curr_info = ninfo(curr);
1707 curr_info.parent = next;
1708 curr_info.parent_arc = arc_between;
1709
1710 auto arc_src = static_cast<Node *>(arc_between->src_node);
1711 curr_info.arc_from_parent = (arc_src == next);
1712 }
1713
1714 // Link in_subtree to out_subtree via entering arc
1715 auto &sub_info = ninfo(in_subtree);
1716 sub_info.parent = out_subtree;
1717 sub_info.parent_arc = entering;
1718 sub_info.arc_from_parent = (static_cast<Node *>(entering->src_node) == out_subtree);
1719
1720 // Update depths and potentials using BFS from in_subtree
1722 queue.put(in_subtree);
1723
1724 auto &out_info = ninfo(out_subtree);
1725 sub_info.depth = out_info.depth + 1;
1726 if (sub_info.arc_from_parent)
1727 sub_info.potential = out_info.potential - entering->cost;
1728 else
1729 sub_info.potential = out_info.potential + entering->cost;
1730
1731 while (not queue.is_empty())
1732 {
1733 Node *curr = queue.get();
1734 const auto &curr_info = ninfo(curr);
1735
1736 // Find children of curr (nodes whose parent is curr)
1737 for (typename Net::Node_Iterator nit(net); nit.has_curr(); nit.next_ne())
1738 {
1739 Node *child = nit.get_curr();
1740 if (child == curr)
1741 continue;
1742
1743 if (parent(child) != curr)
1744 continue;
1745
1746 auto &ci = ninfo(child);
1747 ci.depth = curr_info.depth + 1;
1748
1749 Arc *pa = parent_arc(child);
1750 if (ci.arc_from_parent)
1751 ci.potential = curr_info.potential - pa->cost;
1752 else
1753 ci.potential = curr_info.potential + pa->cost;
1754
1755 queue.put(child);
1756 }
1757 }
1758 }
1759
1760 public:
1766
1782
1789 {
1790 return ainfo(a).lower_bound;
1791 }
1792
1799 {
1800 return std::abs(a->flow - ainfo(a).lower_bound) < eps();
1801 }
1802
1809 {
1810 return std::abs(a->flow - a->cap) < eps();
1811 }
1812
1819 {
1820 return a->cap - a->flow;
1821 }
1822
1829 {
1830 return a->flow - ainfo(a).lower_bound;
1831 }
1832
1833
1834 public:
1844 {
1846 << "Network is not single source and single sink";
1847
1848 stats.reset();
1849 auto total_start = std::chrono::high_resolution_clock::now();
1850
1853
1854 // Count initial partial-flow arcs
1856
1857 // PHASE I: Establish valid basic feasible solution
1858 auto phase1_start = std::chrono::high_resolution_clock::now();
1859 size_t phase1_pivots = force_partial_arcs_into_tree();
1860 auto phase1_end = std::chrono::high_resolution_clock::now();
1861 stats.phase1_time_ms = std::chrono::duration<double, std::milli>(
1862 phase1_end - phase1_start).count();
1863 stats.phase1_pivots = phase1_pivots;
1864 stats.forced_into_tree = phase1_pivots;
1865
1866 // PHASE II: Optimize cost using standard Network Simplex
1867 auto phase2_start = std::chrono::high_resolution_clock::now();
1868 num_pivots = phase1_pivots;
1869 size_t failed_attempts = 0;
1870 const size_t max_pivots = net.vsize() * net.esize() * 10 + 1000;
1871 const size_t max_failures = net.esize() + 1;
1872
1874 {
1876
1877 if (entering == nullptr)
1878 break; // Optimal!
1879
1880 Flow_Type delta;
1881 Arc *leaving;
1882 bool leaving_goes_lower;
1883
1885
1886 if (success)
1887 {
1888 if (std::abs(delta) < eps())
1890
1892 ++num_pivots;
1893 failed_attempts = 0;
1894
1895 // Reset skip flags after successful pivot
1896 for (typename Net::Arc_Iterator ait(net); ait.has_curr(); ait.next_ne())
1897 ainfo(ait.get_curr()).skip = false;
1898 }
1899 else
1900 {
1901 ainfo(entering).skip = true;
1903 }
1904 }
1905
1906 auto phase2_end = std::chrono::high_resolution_clock::now();
1907 stats.phase2_time_ms = std::chrono::duration<double, std::milli>(
1908 phase2_end - phase2_start).count();
1909 stats.phase2_pivots = num_pivots - phase1_pivots;
1910
1911 auto total_end = std::chrono::high_resolution_clock::now();
1912 stats.total_time_ms = std::chrono::duration<double, std::milli>(
1913 total_end - total_start).count();
1915
1916 // Count tree arcs
1917 stats.tree_arcs = 0;
1918 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1919 if (ainfo(it.get_curr()).state == Simplex_Arc_State::Tree)
1920 ++stats.tree_arcs;
1921
1922 return num_pivots;
1923 }
1924
1926 [[nodiscard]] size_t get_num_pivots() const { return num_pivots; }
1927
1930
1932 void print_stats() const
1933 {
1934 std::cout << "=== Network Simplex Statistics ===\n"
1935 << "Total pivots: " << stats.total_pivots << "\n"
1936 << " Phase I pivots: " << stats.phase1_pivots << "\n"
1937 << " Phase II pivots: " << stats.phase2_pivots << "\n"
1938 << " Degenerate pivots: " << stats.degenerate_pivots << "\n"
1939 << "Tree arcs: " << stats.tree_arcs << " (expected " << (net.vsize() - 1) << ")\n"
1940 << "Initial partial-flow arcs: " << stats.initial_partial_arcs << "\n"
1941 << "Arcs forced into tree: " << stats.forced_into_tree << "\n"
1942 << "Timing:\n"
1943 << " Phase I: " << stats.phase1_time_ms << " ms\n"
1944 << " Phase II: " << stats.phase2_time_ms << " ms\n"
1945 << " Total: " << stats.total_time_ms << " ms\n";
1946 }
1947
1961 {
1962 size_t forced_pivots = 0;
1963 bool made_progress = true;
1964
1965 while (made_progress)
1966 {
1967 made_progress = false;
1968
1969 // Find a non-tree arc with partial flow
1970 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
1971 {
1972 auto a = it.get_curr();
1973 if (ainfo(a).state == Simplex_Arc_State::Tree)
1974 continue;
1975
1976 if (not is_partial_flow(a))
1977 continue;
1978
1979 // Found a partial-flow arc not in tree - force it in
1980 // Mark it as Lower (to increase flow direction)
1982
1983 Flow_Type delta;
1984 Arc *leaving;
1985 bool leaving_goes_lower;
1986
1987 // Try to find a valid cycle and leaving arc
1989
1990 if (success and leaving != nullptr and leaving != a)
1991 {
1992 // Verify leaving arc is in tree
1994 {
1996 continue;
1997 }
1998
2000 ++forced_pivots;
2001 made_progress = true;
2002 break;
2003 }
2004 else
2005 {
2006 // Try the other direction (Upper = decrease flow)
2009
2010 if (success and leaving != nullptr and leaving != a)
2011 {
2013 ++forced_pivots;
2014 made_progress = true;
2015 break;
2016 }
2017 else
2018 {
2019 // Cannot add this arc - restore to appropriate bound
2020 if (a->flow <= eps())
2022 else if (a->flow >= a->cap - eps())
2024 else
2025 ainfo(a).state = Simplex_Arc_State::Lower; // Should not happen
2026 }
2027 }
2028 }
2029 }
2030
2031 return forced_pivots;
2032 }
2033
2043 {
2044 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2045 {
2046 auto a = it.get_curr();
2047 if (ainfo(a).state == Simplex_Arc_State::Tree)
2048 continue;
2049
2050 // Non-tree arc must be at bounds
2051 if (is_partial_flow(a))
2052 return false;
2053 }
2054 return true;
2055 }
2056
2059 {
2060 size_t count = 0;
2061 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2062 {
2063 auto a = it.get_curr();
2065 ++count;
2066 }
2067 return count;
2068 }
2069
2078 {
2079 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2080 {
2081 auto a = it.get_curr();
2082 if (ainfo(a).state != Simplex_Arc_State::Tree)
2083 continue;
2084
2085 auto rc = reduced_cost(a);
2086 if (std::abs(rc) > eps() * 100) // Allow small tolerance
2087 return false;
2088 }
2089 return true;
2090 }
2091
2097 {
2098 for (typename Net::Node_Iterator it(net); it.has_curr(); it.next_ne())
2099 {
2100 auto p = it.get_curr();
2101 if (p == root)
2102 continue;
2103
2104 auto pa = parent_arc(p);
2105 if (pa == nullptr)
2106 return false;
2107
2108 if (ainfo(pa).state != Simplex_Arc_State::Tree)
2109 return false;
2110 }
2111 return true;
2112 }
2113
2116 {
2117 std::cout << "\n=== Network Simplex Diagnostics ===\n";
2118
2119 // Count arc types
2120 size_t tree_arcs = 0, lower_arcs = 0, upper_arcs = 0;
2121 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2122 {
2123 switch (ainfo(it.get_curr()).state)
2124 {
2125 case Simplex_Arc_State::Tree: ++tree_arcs; break;
2126 case Simplex_Arc_State::Lower: ++lower_arcs; break;
2127 case Simplex_Arc_State::Upper: ++upper_arcs; break;
2128 }
2129 }
2130
2131 std::cout << "Arcs: Tree=" << tree_arcs << " Lower=" << lower_arcs
2132 << " Upper=" << upper_arcs << " Total=" << net.esize() << "\n";
2133 std::cout << "Expected tree arcs: " << (net.vsize() - 1) << "\n";
2134
2135 // Verify tree reduced costs
2137 std::cout << "Tree arcs rc=0: " << (tree_rc_ok ? "YES" : "NO") << "\n";
2138
2139 // Check for optimality violations
2140 size_t violations = 0;
2141 for (typename Net::Arc_Iterator it(net); it.has_curr(); it.next_ne())
2142 {
2143 auto a = it.get_curr();
2144 auto state = ainfo(a).state;
2145 auto rc = reduced_cost(a);
2146
2147 if (state == Simplex_Arc_State::Lower)
2148 {
2149 // Lower: flow=0, can increase. Optimal if rc >= 0
2150 if (rc < -eps() and a->flow < a->cap - eps())
2151 {
2152 ++violations;
2153 std::cout << " VIOLATION: Lower arc with rc=" << rc
2154 << " flow=" << a->flow << "/" << a->cap << "\n";
2155 }
2156 }
2157 else if (state == Simplex_Arc_State::Upper)
2158 {
2159 // Upper: flow=cap, can decrease. Optimal if rc <= 0
2160 if (rc > eps() and a->flow > eps())
2161 {
2162 ++violations;
2163 std::cout << " VIOLATION: Upper arc with rc=" << rc
2164 << " flow=" << a->flow << "/" << a->cap << "\n";
2165 }
2166 }
2167 }
2168
2169 std::cout << "Optimality violations: " << violations << "\n";
2170 std::cout << "==================================\n";
2171 }
2172 };
2173
2174
2212 template <class Net,
2213 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
2215 {
2216 Max_Flow_Algo<Net>()(net); // First compute maximum flow
2218 return simplex.run();
2219 }
2220
2221
2230 template <class Net,
2231 template <class> class Max_Flow_Algo = Ford_Fulkerson_Maximum_Flow>
2244
2245} // end namespace Aleph
2246
2247# 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:522
WeightedDigraph::Arc Arc
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:1645
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.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
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).
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
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:1750
Path on a graph.
Definition tpl_graph.H:2669
bool is_cycle() const
Return true if this is a cycle; throws if path is empty.
Definition tpl_graph.H:3160
bool is_empty() const noexcept
Return true if the path is empty.
Definition tpl_graph.H:2813
void for_each_arc(Operation op=Operation()) const
Execute an operation on each arc of path.
Definition tpl_graph.H:3342
Container< Arc * > arcs() const
Return a container with all the arcs of the graph.
Definition graph-dry.H:2738
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:772
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
Container< Node * > nodes() const
Return a container with all the nodes of the graph.
Definition graph-dry.H:2720
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
Graph visualization and output generation utilities.
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
#define NODE_COUNTER(p)
Get the counter of a node.
#define NODE_COOKIE(p)
Return the node cookie
Container< T > arcs_map(GT &g, std::function< T(typename GT::Arc *)> transformation, SA sa=SA())
Map the filtered arcs of a graph to a transformed type.
Definition tpl_graph.H:1393
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.
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:1394
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:175
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.
DynList< T > maps(const C &c, Op op)
Classic map operation.
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:1164
Iterator over arcs of a graph.
Definition tpl_agraph.H:325
Functor wrapper for ford_fulkerson_maximum_flow().
Definition tpl_net.H:1535
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:93
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.
Definition tpl_netcost.H:98
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
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:732
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:1119
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) and bridges.
Dynamic key-value map based on balanced binary search trees.
Path finding algorithms in graphs.
Network flow graph structures.