Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_mincost.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
69#ifndef TPL_MINCOST_H
70#define TPL_MINCOST_H
71
72# include <ah-graph-concepts.H>
73
74#include <limits>
75#include <queue>
76#include <functional>
77#include <tpl_netcost.H>
78#include <tpl_array.H>
79#include <tpl_dynBinHeap.H>
80#include <ah-errors.H>
81
82namespace Aleph {
83
84//==============================================================================
85// SUCCESSIVE SHORTEST PATHS (SSP) ALGORITHM
86//==============================================================================
87
94template <typename Flow_Type>
96{
99 bool in_tree{false};
100 void *parent_arc{nullptr};
101 void *parent_node{nullptr};
102 bool forward{true};
103
104 void reset()
105 {
106 distance = std::numeric_limits<Flow_Type>::max();
107 in_tree = false;
108 parent_arc = nullptr;
109 parent_node = nullptr;
110 }
111};
112
116template <class Net>
118{
119 return *static_cast<SSP_Node_Info<typename Net::Flow_Type> *>(NODE_COOKIE(p));
120}
121
132template <class Net>
133typename Net::Flow_Type reduced_cost(const Net &net, typename Net::Arc *arc, bool forward)
134{
135 using Flow_Type = typename Net::Flow_Type;
136
137 auto src = net.get_src_node(arc);
138 auto tgt = net.get_tgt_node(arc);
139
140 Flow_Type pi_src = ssp_info<Net>(src).potential;
141 Flow_Type pi_tgt = ssp_info<Net>(tgt).potential;
142
143 // Forward arc: src -> tgt with cost arc->cost
144 // Reduced cost = cost + π(src) - π(tgt)
145 if (forward)
146 return arc->cost + pi_src - pi_tgt;
147
148 // Backward arc: tgt -> src with cost -arc->cost
149 // Reduced cost = -cost + π(tgt) - π(src)
150 return -arc->cost + pi_tgt - pi_src;
151}
152
160template <class Net>
161bool ssp_shortest_path(Net &net, typename Net::Node *source, typename Net::Node *sink)
162{
163 using Node = typename Net::Node;
164 using Arc = typename Net::Arc;
165 using Flow_Type = typename Net::Flow_Type;
166
167 const Flow_Type INF = std::numeric_limits<Flow_Type>::max();
168
169 // Reset distances
170 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
171 ssp_info<Net>(it.get_curr()).reset();
172
173 ssp_info<Net>(source).distance = 0;
174
175 // Priority queue: (distance, node)
176 using PQ_Entry = std::pair<Flow_Type, Node *>;
178
179 pq.insert({0, source});
180
181 while (not pq.is_empty())
182 {
183 auto [dist, u] = pq.getMin();
184
185 if (dist > ssp_info<Net>(u).distance)
186 continue; // Outdated entry
187
188 // Explore all adjacent arcs
189 for (typename Net::Node_Arc_Iterator it(u); it.has_curr(); it.next_ne())
190 {
191 Arc *arc = it.get_curr();
192 Node *v = net.get_connected_node(arc, u);
193
194 // Determine direction and residual capacity
195 bool forward = (net.get_src_node(arc) == u);
196 Flow_Type residual = forward ? (arc->cap - arc->flow) : arc->flow;
197
198 if (residual <= Flow_Type{0})
199 continue;
200
201 // Compute reduced cost
202 Flow_Type rc = reduced_cost<Net>(net, arc, forward);
203
204 // Relaxation (saturate to avoid integer overflow)
205 const Flow_Type INF_D = std::numeric_limits<Flow_Type>::max();
206 const Flow_Type ud = ssp_info<Net>(u).distance;
208 if constexpr (std::is_integral_v<Flow_Type>)
209 new_dist = (rc > 0 and ud > INF_D - rc) ? INF_D : ud + rc;
210 else
211 new_dist = ud + rc;
212 if (new_dist < ssp_info<Net>(v).distance)
213 {
214 ssp_info<Net>(v).distance = new_dist;
215 ssp_info<Net>(v).parent_arc = arc;
216 ssp_info<Net>(v).parent_node = u;
217 ssp_info<Net>(v).forward = forward;
218 pq.insert({new_dist, v});
219 }
220 }
221 }
222
223 return ssp_info<Net>(sink).distance < INF;
224}
225
268template <class Net>
269std::pair<typename Net::Flow_Type, typename Net::Flow_Type> successive_shortest_paths(Net &net);
270
282template <class Net>
283bool ssp_init_potentials(Net &net, typename Net::Node *source)
284{
285 using Flow_Type = typename Net::Flow_Type;
286
287 const Flow_Type INF = std::numeric_limits<Flow_Type>::max();
288 const Flow_Type LOWEST = std::numeric_limits<Flow_Type>::lowest();
289 const size_t n = net.vsize();
290
291 // Overflow-safe addition/subtraction clamped to [LOWEST, INF].
292 auto sat_add = [INF, LOWEST](Flow_Type a, Flow_Type b) noexcept -> Flow_Type {
293 if constexpr (std::is_integral_v<Flow_Type>) {
294 if (b > 0 and a > INF - b) return INF;
295 if (b < 0 and a < LOWEST - b) return LOWEST;
296 }
297 return a + b;
298 };
299 auto sat_sub = [INF, LOWEST](Flow_Type a, Flow_Type b) noexcept -> Flow_Type {
300 if constexpr (std::is_integral_v<Flow_Type>) {
301 if (b < 0 and a > INF + b) return INF;
302 if (b > 0 and a < LOWEST + b) return LOWEST;
303 }
304 return a - b;
305 };
306
307 // Initialize distances
308 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
309 ssp_info<Net>(it.get_curr()).potential = INF;
310 ssp_info<Net>(source).potential = 0;
311
312 // Bellman-Ford: relax all edges n-1 times
313 for (size_t i = 0; i < n - 1; ++i)
314 {
315 bool changed = false;
316 for (Arc_Iterator<Net> it(net); it.has_curr(); it.next_ne())
317 {
318 auto arc = it.get_curr();
319 auto src = net.get_src_node(arc);
320 auto tgt = net.get_tgt_node(arc);
321
322 // Forward arc (if has residual capacity)
323 if (arc->cap > arc->flow)
324 {
325 Flow_Type d = ssp_info<Net>(src).potential;
326 if (d < INF)
327 {
328 Flow_Type new_d = sat_add(d, arc->cost);
329 if (new_d < ssp_info<Net>(tgt).potential)
330 {
331 ssp_info<Net>(tgt).potential = new_d;
332 changed = true;
333 }
334 }
335 }
336
337 // Backward arc (if has flow to cancel)
338 if (arc->flow > 0)
339 {
340 Flow_Type d = ssp_info<Net>(tgt).potential;
341 if (d < INF)
342 {
343 Flow_Type new_d = sat_sub(d, arc->cost); // backward: cost is negated
344 if (new_d < ssp_info<Net>(src).potential)
345 {
346 ssp_info<Net>(src).potential = new_d;
347 changed = true;
348 }
349 }
350 }
351 }
352 if (not changed)
353 break;
354 }
355
356 // Negative-cycle detection: one extra relaxation pass.
357 // If any edge can still be relaxed, a negative cycle is reachable.
358 for (Arc_Iterator<Net> it(net); it.has_curr(); it.next_ne())
359 {
360 auto arc = it.get_curr();
361 auto src = net.get_src_node(arc);
362 auto tgt = net.get_tgt_node(arc);
363
364 if (arc->cap > arc->flow)
365 {
366 Flow_Type d = ssp_info<Net>(src).potential;
367 if (d < INF and sat_add(d, arc->cost) < ssp_info<Net>(tgt).potential)
368 return false;
369 }
370
371 if (arc->flow > 0)
372 {
373 Flow_Type d = ssp_info<Net>(tgt).potential;
374 if (d < INF and sat_sub(d, arc->cost) < ssp_info<Net>(src).potential)
375 return false;
376 }
377 }
378
379 // Set unreachable nodes to 0 (they won't affect anything)
380 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
381 if (ssp_info<Net>(it.get_curr()).potential >= INF)
382 ssp_info<Net>(it.get_curr()).potential = 0;
383
384 return true;
385}
386
387template <FlowNetwork Net>
388std::pair<typename Net::Flow_Type, typename Net::Flow_Type> successive_shortest_paths(Net &net)
389{
390 using Node = typename Net::Node;
391 using Arc = typename Net::Arc;
392 using Flow_Type = typename Net::Flow_Type;
393
395 << "Network must have single source and single sink";
396
397 Node *source = net.get_source();
398 Node *sink = net.get_sink();
399
400 // Allocate node info; fixed size, no reallocation, so element addresses are stable
402 size_t idx = 0;
403 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne(), ++idx)
404 NODE_COOKIE(it.get_curr()) = &node_info[idx];
405
406 // RAII: clear node cookies on every exit path so callers never see
407 // dangling pointers into the local node_info vector.
408 struct CookieClearer
409 {
410 Net &net_;
412 {
413 for (Node_Iterator<Net> it(net_); it.has_curr(); it.next_ne())
414 NODE_COOKIE(it.get_curr()) = nullptr;
415 }
416 } cookie_clearer{net};
417
418 // Initialize potentials using Bellman-Ford to handle possible negative costs
420 << "successive_shortest_paths: negative-cost cycle detected in residual graph";
421
422 Flow_Type total_flow{0};
423 Flow_Type total_cost{0};
424
425 // Main loop: find shortest augmenting paths
426 while (ssp_shortest_path(net, source, sink))
427 {
428 // Find minimum residual capacity on path
429 Flow_Type path_flow = std::numeric_limits<Flow_Type>::max();
430 for (Node *v = sink; v != source;)
431 {
432 Arc *arc = static_cast<Arc *>(ssp_info<Net>(v).parent_arc);
433 bool forward = ssp_info<Net>(v).forward;
434
435 Flow_Type residual = forward ? (arc->cap - arc->flow) : arc->flow;
436 path_flow = std::min(path_flow, residual);
437
438 v = static_cast<Node *>(ssp_info<Net>(v).parent_node);
439 }
440
441 // Augment flow and compute cost
442 for (Node *v = sink; v != source;)
443 {
444 Arc *arc = static_cast<Arc *>(ssp_info<Net>(v).parent_arc);
445
446 if (bool forward = ssp_info<Net>(v).forward)
447 {
448 arc->flow += path_flow;
449 total_cost += path_flow * arc->cost;
450 }
451 else
452 {
453 arc->flow -= path_flow;
454 total_cost -= path_flow * arc->cost;
455 }
456
457 v = static_cast<Node *>(ssp_info<Net>(v).parent_node);
458 }
459
460 total_flow += path_flow;
461
462 // Update potentials for reachable nodes; track max updated potential
463 // and max finite distance for the unreachable-node shift below.
464 Flow_Type max_potential = std::numeric_limits<Flow_Type>::lowest();
466 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
467 if (auto p = it.get_curr(); ssp_info<Net>(p).distance < std::numeric_limits<Flow_Type>::max())
468 {
469 max_distance = std::max(max_distance, ssp_info<Net>(p).distance);
470 ssp_info<Net>(p).potential += ssp_info<Net>(p).distance;
471 max_potential = std::max(max_potential, ssp_info<Net>(p).potential);
472 }
473
474 // Unreachable nodes are assigned potential = max_potential + max_distance.
475 // This ensures that for any residual arc (u→v) with u unreachable and v
476 // reachable, the reduced cost remains non-negative: the shift by
477 // max_distance dominates the largest finite d(v) seen in Dijkstra.
478 // Saturate to avoid integer overflow when both terms are large.
480 if constexpr (std::is_integral_v<Flow_Type>)
481 {
482 const Flow_Type INF_P = std::numeric_limits<Flow_Type>::max();
485 ? INF_P
487 }
488 else
490
491 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
492 if (auto p = it.get_curr();
493 ssp_info<Net>(p).distance >= std::numeric_limits<Flow_Type>::max())
495 }
496
497 return {total_flow, total_cost};
498}
499
503template <class Net>
505{
506 std::pair<typename Net::Flow_Type, typename Net::Flow_Type> operator()(Net &net) const
507 {
508 return successive_shortest_paths(net);
509 }
510};
511
512//==============================================================================
513// MINIMUM COST FLOW WITH DEMAND (TRANSSHIPMENT)
514//==============================================================================
515
524template <typename Flow_Type>
529
533template <typename Flow_Type>
540
581template <class Net, class GetDemand>
583{
584 using Node = typename Net::Node;
585 using Flow_Type = typename Net::Flow_Type;
586
588
589 // Calculate total supply and demand
590 Flow_Type total_supply{0};
591 Flow_Type total_demand{0};
592
593 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
594 {
595 Flow_Type d = get_demand(it.get_curr());
596 if (d > 0)
597 total_supply += d;
598 else
599 total_demand -= d;
600 }
601
602 // Check balance
603 if (total_supply != total_demand)
604 {
605 result.feasible = false;
606 return result;
607 }
608
609 // Zero total flow: trivially feasible with no flow needed.
610 if (total_supply == Flow_Type{0})
611 {
612 result.feasible = true;
613 return result;
614 }
615
616 // RAII guard: removes super nodes (and all incident arcs) on every exit path.
617 // src_/snk_ are set incrementally so a throw during the second insert_node()
618 // still cleans up the first node.
619 struct SuperNodeGuard
620 {
621 Net &net_;
622 Node *src_{nullptr};
623 Node *snk_{nullptr};
625 {
626 if (snk_)
628 if (src_)
629 net_.remove_node(src_);
630 }
631 } guard{net};
632
633 // Create super-source and super-sink
634 guard.src_ = net.insert_node();
635 Node *super_source = guard.src_;
636 guard.snk_ = net.insert_node();
637 Node *super_sink = guard.snk_;
638
639 // Connect super-source to supply nodes
640 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
641 {
642 Node *p = it.get_curr();
643 if (p == super_source or p == super_sink)
644 continue;
645
646 Flow_Type d = get_demand(p);
647 if (d > 0)
648 net.insert_arc(super_source, p, d, Flow_Type{0}); // zero cost
649 else if (d < 0)
650 net.insert_arc(p, super_sink, -d, Flow_Type{0}); // zero cost
651 }
652
653 // Source and sink are detected automatically by network topology
654
655 // Solve min-cost max-flow
656 auto [flow, cost] = successive_shortest_paths(net);
657
658 result.total_flow = flow;
659 result.total_cost = cost;
660 result.feasible = (flow == total_supply);
661
662 return result;
663}
664
665//==============================================================================
666// ASSIGNMENT PROBLEM
667//==============================================================================
668
672template <typename Cost_Type>
679
715template <typename Cost_Type>
716AssignmentResult<Cost_Type> solve_assignment(const std::vector<std::vector<Cost_Type>> &costs)
717{
719 using Node = typename Net::Node;
720
722
723 size_t n = costs.size();
724 if (n == 0)
725 {
726 result.feasible = true;
727 return result;
728 }
729
730 // Verify square matrix: a non-square costs matrix is malformed input.
731 for (const auto &row : costs)
732 ah_invalid_argument_if(row.size() != n)
733 << "solve_assignment: costs matrix is not square (" << n << " x " << row.size() << ")";
734
735 Net net;
736
737 // Create source and sink
738 Node *source = net.insert_node();
739 Node *sink = net.insert_node();
740
741 // Create worker nodes
742 auto workers = Array<Node *>::create(n);
743 for (size_t i = 0; i < n; ++i)
744 {
745 workers[i] = net.insert_node();
746 net.insert_arc(source, workers[i], Cost_Type{1}, Cost_Type{0});
747 }
748
749 // Create task nodes
750 auto tasks = Array<Node *>::create(n);
751 DynMapTree<Node *, size_t> taskIndex; // Reverse lookup: task node -> index
752 for (size_t j = 0; j < n; ++j)
753 {
754 tasks[j] = net.insert_node();
755 taskIndex.insert(tasks[j], j);
756 net.insert_arc(tasks[j], sink, Cost_Type{1}, Cost_Type{0});
757 }
758
759 // Create worker-task arcs with costs
760 for (size_t i = 0; i < n; ++i)
761 for (size_t j = 0; j < n; ++j)
762 net.insert_arc(workers[i], tasks[j], Cost_Type{1}, costs[i][j]);
763
764 // Source and sink are detected automatically by network topology
765
766 // Solve
767 auto [flow, cost] = successive_shortest_paths(net);
768
769 result.feasible = (static_cast<size_t>(flow) == n);
770 result.total_cost = cost;
771
772 // Extract assignments from flow
773 if (result.feasible)
774 for (size_t i = 0; i < n; ++i)
775 for (typename Net::Node_Arc_Iterator it(workers[i]); it.has_curr(); it.next_ne())
776 {
777 auto arc = it.get_curr();
778 if (arc->flow <= 0)
779 continue;
780 auto tgt = net.get_tgt_node(arc);
781
782 // O(log n) lookup instead of O(n) linear search
783 if (taskIndex.contains(tgt))
784 {
785 size_t j = taskIndex.find(tgt);
786 result.assignments.append(std::make_pair(i, j));
787 }
788 }
789
790 return result;
791}
792
793//==============================================================================
794// TRANSPORTATION PROBLEM
795//==============================================================================
796
800template <typename Cost_Type>
802{
803 bool feasible{false};
805 std::vector<std::vector<Cost_Type>> shipments;
806};
807
842template <typename Cost_Type>
844 const std::vector<Cost_Type> &demands,
845 const std::vector<std::vector<Cost_Type>> &costs)
846{
848 using Node = typename Net::Node;
849 using Arc = typename Net::Arc;
850
852
853 size_t m = supplies.size(); // sources
854 size_t n = demands.size(); // destinations
855
856 // Validate costs matrix dimensions
858 << "solve_transportation: costs has " << costs.size() << " rows but " << m << " supply points";
859 for (size_t i = 0; i < m; ++i)
861 << "solve_transportation: costs[" << i << "] has " << costs[i].size() << " columns but " << n
862 << " demand points";
863
864 // Validate non-negative supplies and demands
865 for (size_t i = 0; i < m; ++i)
867 << "solve_transportation: supplies[" << i << "] is negative";
868 for (size_t j = 0; j < n; ++j)
870 << "solve_transportation: demands[" << j << "] is negative";
871
872 // Compute totals first — needed both for the early-exit guard and the
873 // balance check that follows.
874 Cost_Type total_supply = Cost_Type{0};
875 Cost_Type total_demand = Cost_Type{0};
876 for (auto s : supplies)
877 total_supply += s;
878 for (auto d : demands)
879 total_demand += d;
880
881 // If either side is empty no graph can be built. Return immediately based
882 // on whether the totals are balanced (feasible iff both are zero).
883 if (m == 0 or n == 0)
884 {
885 result.feasible = (total_supply == total_demand);
886 return result;
887 }
888
889 // Check supply-demand balance for the non-trivial case.
890 if (total_supply != total_demand)
891 {
892 result.feasible = false;
893 return result;
894 }
895
896 Net net;
897
898 // Create source and sink
899 Node *source = net.insert_node();
900 Node *sink = net.insert_node();
901
902 // Create supply nodes
903 std::vector<Node *> supply_nodes(m);
904 for (size_t i = 0; i < m; ++i)
905 {
906 supply_nodes[i] = net.insert_node();
907 net.insert_arc(source, supply_nodes[i], supplies[i], Cost_Type{0});
908 }
909
910 // Create demand nodes
911 std::vector<Node *> demand_nodes(n);
912 for (size_t j = 0; j < n; ++j)
913 {
914 demand_nodes[j] = net.insert_node();
915 net.insert_arc(demand_nodes[j], sink, demands[j], Cost_Type{0});
916 }
917
918 // Create arcs between supplies and demands
919 // Store arcs for extracting solution
920 std::vector<std::vector<Arc *>> arcs(m, std::vector<Arc *>(n));
921 for (size_t i = 0; i < m; ++i)
922 for (size_t j = 0; j < n; ++j)
923 arcs[i][j] = net.insert_arc(supply_nodes[i],
924 demand_nodes[j],
925 std::min(supplies[i], demands[j]),
926 costs[i][j]);
927
928 // Source and sink are detected automatically by network topology
929
930 // Solve
931 auto [flow, cost] = successive_shortest_paths(net);
932
933 result.feasible = (flow == total_supply);
934 result.total_cost = cost;
935
936 // Extract shipments
937 result.shipments.resize(m, std::vector<Cost_Type>(n, Cost_Type{0}));
938 for (size_t i = 0; i < m; ++i)
939 for (size_t j = 0; j < n; ++j)
940 result.shipments[i][j] = arcs[i][j]->flow;
941
942 return result;
943}
944
945//==============================================================================
946// MIN-COST FLOW STATISTICS
947//==============================================================================
948
952template <typename Flow_Type>
954{
957 size_t iterations{0};
958 size_t augmentations{0};
959 double elapsed_ms{0};
960
961 void print() const
962 {
963 std::cout << "=== Min-Cost Flow Statistics ===\n"
964 << "Max flow: " << max_flow << "\n"
965 << "Min cost: " << min_cost << "\n"
966 << "Iterations: " << iterations << "\n"
967 << "Augmentations: " << augmentations << "\n"
968 << "Time: " << elapsed_ms << " ms\n";
969 }
970};
971
972//==============================================================================
973// WARM START FOR NETWORK SIMPLEX
974//==============================================================================
975
987template <class Net>
989{
991
992 for (Arc_Iterator<Net> it(net); it.has_curr(); it.next_ne())
993 {
994 auto arc = it.get_curr();
995 solution[arc] = arc->flow;
996 }
997
998 return solution;
999}
1000
1012template <class Net>
1015{
1016 for (Arc_Iterator<Net> it(net); it.has_curr(); it.next_ne())
1017 {
1018 auto arc = it.get_curr();
1019 if (solution.has(arc))
1020 arc->flow = solution[arc];
1021 }
1022}
1023
1024} // namespace Aleph
1025
1026#endif // TPL_MINCOST_H
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
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:644
C++20 concepts for the protocol shared by graph algorithms.
WeightedDigraph::Node Node
WeightedDigraph::Arc Arc
size_t row
Definition ca-c-api.h:115
bool has_curr() const noexcept
Check if there is a current valid item.
Definition array_it.H:231
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
Dynamic heap of elements of type T ordered by a comparison functor.
T & insert(const T &item)
Insert a copy of item into the heap.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Generic key-value map implemented on top of a binary search tree.
bool has(const Key &key) const noexcept
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1207
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:779
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
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
constexpr size_t size() const noexcept
Returns the number of entries in the table.
Definition hashDry.H:619
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
#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
double Flow_Type
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t size(Node *root) noexcept
bool ssp_init_potentials(Net &net, typename Net::Node *source)
Initialize potentials using Bellman-Ford.
and
Check uniqueness with explicit hash + equality functors.
void restore_flow_solution(Net &net, const DynMapTree< typename Net::Arc *, typename Net::Flow_Type > &solution)
Restore network simplex solution from warm start.
TransportationResult< Cost_Type > solve_transportation(const std::vector< Cost_Type > &supplies, const std::vector< Cost_Type > &demands, const std::vector< std::vector< Cost_Type > > &costs)
Solve the transportation problem using min-cost flow.
SSP_Node_Info< typename Net::Flow_Type > & ssp_info(typename Net::Node *p) noexcept
Access SSP node info.
TransshipmentResult< typename Net::Flow_Type > solve_transshipment(Net &net, GetDemand get_demand)
Solve minimum cost transshipment problem.
std::pair< typename Net::Flow_Type, typename Net::Flow_Type > successive_shortest_paths(Net &net)
Compute minimum cost maximum flow using Successive Shortest Paths.
AssignmentResult< Cost_Type > solve_assignment(const std::vector< std::vector< Cost_Type > > &costs)
Solve the assignment problem using min-cost flow.
bool ssp_shortest_path(Net &net, typename Net::Node *source, typename Net::Node *sink)
Find shortest path using Dijkstra with potentials.
DynMapTree< typename Net::Arc *, typename Net::Flow_Type > save_flow_solution(const Net &net)
Save network simplex solution for warm start.
Net::Flow_Type reduced_cost(const Net &net, typename Net::Arc *arc, bool forward)
Compute reduced cost of an arc.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1165
Result of assignment problem.
DynList< std::pair< size_t, size_t > > assignments
(worker, task) pairs
Statistics for min-cost flow algorithms.
Arc type for maximum flow minimum cost networks.
Definition tpl_netcost.H:95
Capacitated flow network with costs associated to arcs.
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
Node * get_sink() const
Return an arbitrary sink node.
Definition tpl_net.H:551
typename Arc::Flow_Type Flow_Type
Capacity/flow numeric type.
Definition tpl_net.H:278
void remove_node(Node *p) noexcept override
Remove node p and all its arcs from the network.
Definition tpl_net.H:704
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
Node info for SSP algorithm.
Definition tpl_mincost.H:96
bool forward
Direction of parent arc.
Flow_Type distance
Shortest path distance.
Definition tpl_mincost.H:98
bool in_tree
Is node in shortest path tree?
Definition tpl_mincost.H:99
Flow_Type potential
Node potential for reduced costs.
Definition tpl_mincost.H:97
void * parent_node
Parent node.
void * parent_arc
Parent arc in shortest path tree.
Functor wrapper for SSP algorithm.
std::pair< typename Net::Flow_Type, typename Net::Flow_Type > operator()(Net &net) const
Result of transportation problem.
std::vector< std::vector< Cost_Type > > shipments
shipments[i][j] from i to j
Result of transshipment problem.
Flow_Type total_cost
Total transportation cost.
bool feasible
Is there a feasible solution?
Flow_Type total_flow
Total flow shipped.
Node with supply/demand for transshipment problems.
Flow_Type demand
Positive = supply, negative = demand.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Dynamic array container with automatic resizing.
Dynamic binary heap with node-based storage.
Maximum flow minimum cost network algorithms.