11#include <boost/graph/edmonds_karp_max_flow.hpp>
12#include <boost/graph/push_relabel_max_flow.hpp>
13#include <boost/graph/cycle_canceling.hpp>
14#include <boost/graph/find_flow_cost.hpp>
15#include <boost/graph/successive_shortest_path_nonnegative_weights.hpp>
45template <
typename NodeID>
48 std::map<std::pair<NodeID, NodeID>,
long> flow;
49 std::map<std::size_t, long> edge_flows_by_id;
73template <
typename NodeID>
77 std::map<std::pair<NodeID, NodeID>,
long> edge_flows;
78 std::map<std::size_t, long> edge_flows_by_id;
83template <
typename NodeID,
typename FlowEdgeDesc>
88 FlowEdgeDesc edge_desc;
91template <
typename NodeID,
typename FlowEdgeDesc,
typename CapacityMap,
typename Res
idualMap>
94 const CapacityMap& capacity,
95 const ResidualMap& residual,
96 std::map<std::pair<NodeID, NodeID>,
long>& endpoint_flows,
97 std::map<std::size_t, long>& edge_flows_by_id
99 for (
const auto& edge : original_edges) {
100 const long flow_value = capacity[edge.edge_desc] - residual[edge.edge_desc];
101 endpoint_flows[{edge.source_id, edge.target_id}] += flow_value;
102 edge_flows_by_id[edge.edge_id] = flow_value;
106template <
typename NodeID>
108 using FlowTraits = boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS>;
109 using FlowGraph = boost::adjacency_list<
115 boost::edge_weight_t,
118 boost::edge_capacity_t,
121 boost::edge_residual_capacity_t,
123 boost::property<boost::edge_reverse_t, typename FlowTraits::edge_descriptor>
128 using WeightMap =
typename boost::property_map<FlowGraph, boost::edge_weight_t>::type;
129 using CapacityMap =
typename boost::property_map<FlowGraph, boost::edge_capacity_t>::type;
130 using ResidualMap =
typename boost::property_map<FlowGraph, boost::edge_residual_capacity_t>::type;
131 using ReverseMap =
typename boost::property_map<FlowGraph, boost::edge_reverse_t>::type;
132 using FlowEdgeDesc =
typename boost::graph_traits<FlowGraph>::edge_descriptor;
134 FlowGraph flow_graph;
136 CapacityMap capacity;
137 ResidualMap residual;
139 std::vector<FlowEdgeRecord<NodeID, FlowEdgeDesc>> original_edges;
147 weight(boost::get(boost::edge_weight, flow_graph)),
148 capacity(boost::get(boost::edge_capacity, flow_graph)),
149 residual(boost::get(boost::edge_residual_capacity, flow_graph)),
150 reverse(boost::get(boost::edge_reverse, flow_graph)) {}
153template <
typename GraphWrapper>
154auto& min_cost_flow_cache() {
155 using NodeID =
typename GraphWrapper::NodeType;
156 static std::map<const void*, std::unique_ptr<MinCostFlowState<NodeID>>> cache;
160template <
typename GraphWrapper>
161auto& invalidated_min_cost_flow_graphs() {
162 static std::set<const void*> invalidated;
168template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
170 static void invalidate(
const void* graph_ptr) {
171 auto& cache = detail::min_cost_flow_cache<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>();
172 if (cache.erase(graph_ptr) > 0) {
173 detail::invalidated_min_cost_flow_graphs<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>().insert(graph_ptr);
177 static void clear(
const void* graph_ptr) {
178 auto& cache = detail::min_cost_flow_cache<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>();
179 auto& invalidated = detail::invalidated_min_cost_flow_graphs<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>();
180 cache.erase(graph_ptr);
181 invalidated.erase(graph_ptr);
206template <
typename NodeID>
209 std::vector<NodeID> reachable;
210 std::vector<NodeID> non_reachable;
211 std::vector<std::pair<NodeID, NodeID>> cut_edges;
212 std::vector<std::size_t> cut_edge_ids;
215template <
typename GraphWrapper>
226[[deprecated(
"Use G.edmonds_karp_maximum_flow(source, target, capacity_attr) instead.")]]
227auto edmonds_karp_maximum_flow(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity") {
228 return G.edmonds_karp_maximum_flow(source_id, target_id, capacity_attr);
231template <
typename GraphWrapper>
242[[deprecated(
"Use G.push_relabel_maximum_flow_result(source, target, capacity_attr) instead.")]]
243auto push_relabel_maximum_flow_result(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity") {
244 return G.push_relabel_maximum_flow_result(source_id, target_id, capacity_attr);
247template <
typename GraphWrapper>
258[[deprecated(
"Use G.maximum_flow(source, target, capacity_attr) instead.")]]
259auto maximum_flow(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity") {
260 return G.maximum_flow(source_id, target_id, capacity_attr);
263template <
typename GraphWrapper>
274[[deprecated(
"Use G.minimum_cut(source, target, capacity_attr) instead.")]]
275auto minimum_cut(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity") {
276 return G.minimum_cut(source_id, target_id, capacity_attr);
279template <
typename GraphWrapper>
291[[deprecated(
"Use G.max_flow_min_cost_cycle_canceling(source, target, capacity_attr, weight_attr) instead.")]]
292auto max_flow_min_cost_cycle_canceling(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight") {
293 return G.max_flow_min_cost_cycle_canceling(source_id, target_id, capacity_attr, weight_attr);
296template <
typename GraphWrapper>
308[[deprecated(
"Use G.push_relabel_maximum_flow(source, target, capacity_attr, weight_attr) instead.")]]
309long push_relabel_maximum_flow(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight") {
310 return G.push_relabel_maximum_flow(source_id, target_id, capacity_attr, weight_attr);
313template <
typename GraphWrapper>
321[[deprecated(
"Use G.cycle_canceling(weight_attr) instead.")]]
322auto cycle_canceling(
const GraphWrapper& G,
const std::string& weight_attr =
"weight") {
323 return G.cycle_canceling(weight_attr);
326template <
typename GraphWrapper>
338[[deprecated(
"Use G.successive_shortest_path_nonnegative_weights(source, target, capacity_attr, weight_attr) instead.")]]
339auto successive_shortest_path_nonnegative_weights(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight") {
340 return G.successive_shortest_path_nonnegative_weights(source_id, target_id, capacity_attr, weight_attr);
343template <
typename GraphWrapper>
355[[deprecated(
"Use G.max_flow_min_cost_successive_shortest_path(source, target, capacity_attr, weight_attr) instead.")]]
356auto max_flow_min_cost_successive_shortest_path(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight") {
357 return G.max_flow_min_cost_successive_shortest_path(source_id, target_id, capacity_attr, weight_attr);
359template <
typename GraphWrapper>
371[[deprecated(
"Use G.max_flow_min_cost(source, target, capacity_attr, weight_attr) instead.")]]
372auto max_flow_min_cost(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight") {
373 return G.max_flow_min_cost(source_id, target_id, capacity_attr, weight_attr);
376template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
378 if (!has_node(source_id) || !has_node(target_id))
throw std::runtime_error(
"Flow setup failed: source or target node not found.");
379 using FlowTraits = boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS>;
380 using FlowGraph = boost::adjacency_list<
381 boost::vecS, boost::vecS, boost::directedS, boost::no_property,
382 boost::property<boost::edge_capacity_t, long,
383 boost::property<boost::edge_residual_capacity_t, long,
384 boost::property<boost::edge_reverse_t, typename FlowTraits::edge_descriptor>>>>;
385 using CapacityMap =
typename boost::property_map<FlowGraph, boost::edge_capacity_t>::type;
386 using ResidualMap =
typename boost::property_map<FlowGraph, boost::edge_residual_capacity_t>::type;
387 using ReverseMap =
typename boost::property_map<FlowGraph, boost::edge_reverse_t>::type;
388 using FlowEdgeDesc =
typename boost::graph_traits<FlowGraph>::edge_descriptor;
390 FlowGraph flow_graph;
391 CapacityMap capacity = boost::get(boost::edge_capacity, flow_graph);
392 ReverseMap reverse = boost::get(boost::edge_reverse, flow_graph);
393 const auto& all_nodes = get_bgl_to_id_map();
394 for (std::size_t i = 0; i < all_nodes.size(); ++i) { boost::add_vertex(flow_graph); }
396 std::vector<detail::FlowEdgeRecord<NodeID, FlowEdgeDesc>> original_edges;
397 for (
auto [eit, eend] = boost::edges(g); eit != eend; ++eit) {
398 const auto source = boost::source(*eit, g);
399 const auto target = boost::target(*eit, g);
400 const auto source_index = get_vertex_index(source);
401 const auto target_index = get_vertex_index(target);
402 const auto& u = get_node_id(source);
403 const auto& v = get_node_id(target);
404 const auto edge_id = get_edge_id(*eit);
405 auto [e, added] = boost::add_edge(source_index, target_index, flow_graph);
406 auto [rev, rev_added] = boost::add_edge(target_index, source_index, flow_graph);
407 (void)added; (void)rev_added;
408 capacity[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, capacity_attr));
412 original_edges.push_back({edge_id, u, v, e});
415 const long flow_value = boost::edmonds_karp_max_flow(
417 get_vertex_index(id_to_bgl.at(source_id)),
418 get_vertex_index(id_to_bgl.at(target_id))
420 ResidualMap residual = boost::get(boost::edge_residual_capacity, flow_graph);
422 result.value = flow_value;
423 detail::fill_flow_views(original_edges, capacity, residual, result.flow, result.edge_flows_by_id);
427template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
429 if (!has_node(source_id) || !has_node(target_id))
throw std::runtime_error(
"Flow setup failed: source or target node not found.");
430 using FlowTraits = boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS>;
431 using FlowGraph = boost::adjacency_list<
432 boost::vecS, boost::vecS, boost::directedS, boost::no_property,
433 boost::property<boost::edge_capacity_t, long,
434 boost::property<boost::edge_residual_capacity_t, long,
435 boost::property<boost::edge_reverse_t, typename FlowTraits::edge_descriptor>>>>;
436 using CapacityMap =
typename boost::property_map<FlowGraph, boost::edge_capacity_t>::type;
437 using ResidualMap =
typename boost::property_map<FlowGraph, boost::edge_residual_capacity_t>::type;
438 using ReverseMap =
typename boost::property_map<FlowGraph, boost::edge_reverse_t>::type;
439 using FlowEdgeDesc =
typename boost::graph_traits<FlowGraph>::edge_descriptor;
441 FlowGraph flow_graph;
442 CapacityMap capacity = boost::get(boost::edge_capacity, flow_graph);
443 ReverseMap reverse = boost::get(boost::edge_reverse, flow_graph);
444 const auto& all_nodes = get_bgl_to_id_map();
445 for (std::size_t i = 0; i < all_nodes.size(); ++i) { boost::add_vertex(flow_graph); }
447 std::vector<detail::FlowEdgeRecord<NodeID, FlowEdgeDesc>> original_edges;
448 for (
auto [eit, eend] = boost::edges(g); eit != eend; ++eit) {
449 const auto source = boost::source(*eit, g);
450 const auto target = boost::target(*eit, g);
451 const auto source_index = get_vertex_index(source);
452 const auto target_index = get_vertex_index(target);
453 const auto& u = get_node_id(source);
454 const auto& v = get_node_id(target);
455 const auto edge_id = get_edge_id(*eit);
456 auto [e, added] = boost::add_edge(source_index, target_index, flow_graph);
457 auto [rev, rev_added] = boost::add_edge(target_index, source_index, flow_graph);
458 (void)added; (void)rev_added;
459 capacity[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, capacity_attr));
463 original_edges.push_back({edge_id, u, v, e});
466 const long flow_value = boost::push_relabel_max_flow(
468 get_vertex_index(id_to_bgl.at(source_id)),
469 get_vertex_index(id_to_bgl.at(target_id))
471 ResidualMap residual = boost::get(boost::edge_residual_capacity, flow_graph);
473 result.value = flow_value;
474 detail::fill_flow_views(original_edges, capacity, residual, result.flow, result.edge_flows_by_id);
478template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
479auto Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>::maximum_flow(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr)
const {
return edmonds_karp_maximum_flow(source_id, target_id, capacity_attr); }
481template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
483 if (!has_node(source_id) || !has_node(target_id))
throw std::runtime_error(
"Flow setup failed: source or target node not found.");
484 using FlowTraits = boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS>;
485 using FlowGraph = boost::adjacency_list<
486 boost::vecS, boost::vecS, boost::directedS, boost::no_property,
487 boost::property<boost::edge_capacity_t, long,
488 boost::property<boost::edge_residual_capacity_t, long,
489 boost::property<boost::edge_reverse_t, typename FlowTraits::edge_descriptor>>>>;
490 using CapacityMap =
typename boost::property_map<FlowGraph, boost::edge_capacity_t>::type;
491 using ResidualMap =
typename boost::property_map<FlowGraph, boost::edge_residual_capacity_t>::type;
492 using ReverseMap =
typename boost::property_map<FlowGraph, boost::edge_reverse_t>::type;
494 FlowGraph flow_graph;
495 CapacityMap capacity = boost::get(boost::edge_capacity, flow_graph);
496 ReverseMap reverse = boost::get(boost::edge_reverse, flow_graph);
497 const auto& index_to_node = get_bgl_to_id_map();
498 for (std::size_t i = 0; i < index_to_node.size(); ++i) { boost::add_vertex(flow_graph); }
499 for (
auto [eit, eend] = boost::edges(g); eit != eend; ++eit) {
500 const auto source = boost::source(*eit, g);
501 const auto target = boost::target(*eit, g);
502 const auto source_index = get_vertex_index(source);
503 const auto target_index = get_vertex_index(target);
504 const auto edge_id = get_edge_id(*eit);
505 auto [e, added] = boost::add_edge(source_index, target_index, flow_graph);
506 auto [rev, rev_added] = boost::add_edge(target_index, source_index, flow_graph);
507 (void)added; (void)rev_added;
508 capacity[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, capacity_attr));
513 const auto source_index = get_vertex_index(id_to_bgl.at(source_id));
514 const auto target_index = get_vertex_index(id_to_bgl.at(target_id));
515 const long cut_value = boost::edmonds_karp_max_flow(flow_graph, source_index, target_index);
516 ResidualMap residual = boost::get(boost::edge_residual_capacity, flow_graph);
517 std::vector<bool> visited(index_to_node.size(),
false);
518 std::queue<std::size_t> q;
519 visited[source_index] =
true;
520 q.push(source_index);
522 const auto current = q.front();
524 for (
auto [eit, eend] = boost::out_edges(current, flow_graph); eit != eend; ++eit) {
525 const auto next = boost::target(*eit, flow_graph);
526 if (!visited[next] && residual[*eit] > 0) { visited[next] =
true; q.push(next); }
530 result.value = cut_value;
531 for (std::size_t i = 0; i < index_to_node.size(); ++i) {
532 if (visited[i]) result.reachable.push_back(index_to_node[i]);
533 else result.non_reachable.push_back(index_to_node[i]);
535 for (
auto [eit, eend] = boost::edges(g); eit != eend; ++eit) {
536 const auto source = boost::source(*eit, g);
537 const auto target = boost::target(*eit, g);
538 const auto source_index_for_cut = get_vertex_index(source);
539 const auto target_index_for_cut = get_vertex_index(target);
540 if (visited[source_index_for_cut] && !visited[target_index_for_cut]) {
541 result.cut_edges.emplace_back(get_node_id(source), get_node_id(target));
542 result.cut_edge_ids.push_back(get_edge_id(*eit));
548template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
550 if (!has_node(source_id) || !has_node(target_id))
throw std::runtime_error(
"Flow setup failed: source or target node not found.");
551 using FlowTraits = boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS>;
552 using FlowGraph = boost::adjacency_list<
553 boost::vecS, boost::vecS, boost::directedS, boost::no_property,
554 boost::property<boost::edge_weight_t, long,
555 boost::property<boost::edge_capacity_t, long,
556 boost::property<boost::edge_residual_capacity_t, long,
557 boost::property<boost::edge_reverse_t, typename FlowTraits::edge_descriptor>>>>>;
558 using WeightMap =
typename boost::property_map<FlowGraph, boost::edge_weight_t>::type;
559 using CapacityMap =
typename boost::property_map<FlowGraph, boost::edge_capacity_t>::type;
560 using ResidualMap =
typename boost::property_map<FlowGraph, boost::edge_residual_capacity_t>::type;
561 using ReverseMap =
typename boost::property_map<FlowGraph, boost::edge_reverse_t>::type;
562 using FlowEdgeDesc =
typename boost::graph_traits<FlowGraph>::edge_descriptor;
564 FlowGraph flow_graph;
565 WeightMap weight = boost::get(boost::edge_weight, flow_graph);
566 CapacityMap capacity = boost::get(boost::edge_capacity, flow_graph);
567 ReverseMap reverse = boost::get(boost::edge_reverse, flow_graph);
568 const auto& all_nodes = get_bgl_to_id_map();
569 for (std::size_t i = 0; i < all_nodes.size(); ++i) { boost::add_vertex(flow_graph); }
570 std::vector<detail::FlowEdgeRecord<NodeID, FlowEdgeDesc>> original_edges;
571 for (
auto [eit, eend] = boost::edges(g); eit != eend; ++eit) {
572 const auto source = boost::source(*eit, g);
573 const auto target = boost::target(*eit, g);
574 const auto source_index = get_vertex_index(source);
575 const auto target_index = get_vertex_index(target);
576 const auto& u = get_node_id(source);
577 const auto& v = get_node_id(target);
578 const auto edge_id = get_edge_id(*eit);
579 auto [e, added] = boost::add_edge(source_index, target_index, flow_graph);
580 auto [rev, rev_added] = boost::add_edge(target_index, source_index, flow_graph);
581 (void)added; (void)rev_added;
582 weight[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, weight_attr));
583 weight[rev] = -weight[e];
584 capacity[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, capacity_attr));
588 original_edges.push_back({edge_id, u, v, e});
590 boost::push_relabel_max_flow(
592 get_vertex_index(id_to_bgl.at(source_id)),
593 get_vertex_index(id_to_bgl.at(target_id))
595 boost::cycle_canceling(flow_graph);
596 const long cost = boost::find_flow_cost(flow_graph);
597 ResidualMap residual = boost::get(boost::edge_residual_capacity, flow_graph);
600 detail::fill_flow_views(original_edges, capacity, residual, result.edge_flows, result.edge_flows_by_id);
601 for (
const auto& edge : original_edges) {
602 if (edge.source_id == source_id) {
603 result.flow += result.edge_flows_by_id[edge.edge_id];
609template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
611 if (!has_node(source_id) || !has_node(target_id))
throw std::runtime_error(
"Flow setup failed: source or target node not found.");
612 auto state = std::make_unique<detail::MinCostFlowState<NodeID>>();
613 state->source_id = source_id;
614 state->target_id = target_id;
615 const auto& all_nodes = get_bgl_to_id_map();
616 for (std::size_t i = 0; i < all_nodes.size(); ++i) { boost::add_vertex(state->flow_graph); }
617 for (
auto [eit, eend] = boost::edges(g); eit != eend; ++eit) {
618 const auto source = boost::source(*eit, g);
619 const auto target = boost::target(*eit, g);
620 const auto source_index = get_vertex_index(source);
621 const auto target_index = get_vertex_index(target);
622 const auto& u = get_node_id(source);
623 const auto& v = get_node_id(target);
624 const auto edge_id = get_edge_id(*eit);
625 auto [e, added] = boost::add_edge(source_index, target_index, state->flow_graph);
626 auto [rev, rev_added] = boost::add_edge(target_index, source_index, state->flow_graph);
627 (void)added; (void)rev_added;
628 state->weight[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, weight_attr));
629 state->weight[rev] = -state->weight[e];
630 state->capacity[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, capacity_attr));
631 state->capacity[rev] = 0;
632 state->reverse[e] = rev;
633 state->reverse[rev] = e;
634 state->original_edges.push_back({edge_id, u, v, e});
636 state->value = boost::push_relabel_max_flow(
638 get_vertex_index(id_to_bgl.at(source_id)),
639 get_vertex_index(id_to_bgl.at(target_id))
641 auto& cache = detail::min_cost_flow_cache<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>();
642 auto& invalidated = detail::invalidated_min_cost_flow_graphs<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>();
643 cache[
static_cast<const void*
>(
this)] = std::move(state);
644 invalidated.erase(
static_cast<const void*
>(
this));
645 return cache.at(
static_cast<const void*
>(
this))->value;
648template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
650 auto& cache = detail::min_cost_flow_cache<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>();
651 auto& invalidated = detail::invalidated_min_cost_flow_graphs<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>();
652 auto it = cache.find(
static_cast<const void*
>(
this));
653 if (it == cache.end()) {
654 if (invalidated.contains(
static_cast<const void*
>(
this))) {
655 throw std::runtime_error(
"Min-cost-flow state invalidated by graph mutation: rerun push_relabel_maximum_flow(...) before cycle_canceling().");
657 throw std::runtime_error(
"Min-cost-flow state unavailable: run push_relabel_maximum_flow(...) first.");
659 auto& state = *it->second;
660 for (
const auto& edge : state.original_edges) {
661 state.weight[edge.edge_desc] =
static_cast<long>(get_edge_numeric_attr(edge.edge_id, weight_attr));
662 const auto rev = state.reverse[edge.edge_desc];
663 state.weight[rev] = -state.weight[edge.edge_desc];
665 boost::cycle_canceling(state.flow_graph);
666 state.cost = boost::find_flow_cost(state.flow_graph);
670template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
672 if (!has_node(source_id) || !has_node(target_id))
throw std::runtime_error(
"Flow setup failed: source or target node not found.");
673 using FlowTraits = boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS>;
674 using FlowGraph = boost::adjacency_list<
675 boost::vecS, boost::vecS, boost::directedS, boost::no_property,
676 boost::property<boost::edge_weight_t, long,
677 boost::property<boost::edge_capacity_t, long,
678 boost::property<boost::edge_residual_capacity_t, long,
679 boost::property<boost::edge_reverse_t, typename FlowTraits::edge_descriptor>>>>>;
680 using WeightMap =
typename boost::property_map<FlowGraph, boost::edge_weight_t>::type;
681 using CapacityMap =
typename boost::property_map<FlowGraph, boost::edge_capacity_t>::type;
682 using ResidualMap =
typename boost::property_map<FlowGraph, boost::edge_residual_capacity_t>::type;
683 using ReverseMap =
typename boost::property_map<FlowGraph, boost::edge_reverse_t>::type;
684 using FlowEdgeDesc =
typename boost::graph_traits<FlowGraph>::edge_descriptor;
686 FlowGraph flow_graph;
687 WeightMap weight = boost::get(boost::edge_weight, flow_graph);
688 CapacityMap capacity = boost::get(boost::edge_capacity, flow_graph);
689 ReverseMap reverse = boost::get(boost::edge_reverse, flow_graph);
690 const auto& all_nodes = get_bgl_to_id_map();
691 for (std::size_t i = 0; i < all_nodes.size(); ++i) { boost::add_vertex(flow_graph); }
692 std::vector<detail::FlowEdgeRecord<NodeID, FlowEdgeDesc>> original_edges;
693 for (
auto [eit, eend] = boost::edges(g); eit != eend; ++eit) {
694 const auto source = boost::source(*eit, g);
695 const auto target = boost::target(*eit, g);
696 const auto source_index = get_vertex_index(source);
697 const auto target_index = get_vertex_index(target);
698 const auto& u = get_node_id(source);
699 const auto& v = get_node_id(target);
700 const auto edge_id = get_edge_id(*eit);
701 auto [e, added] = boost::add_edge(source_index, target_index, flow_graph);
702 auto [rev, rev_added] = boost::add_edge(target_index, source_index, flow_graph);
703 (void)added; (void)rev_added;
704 weight[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, weight_attr));
705 weight[rev] = -weight[e];
706 capacity[e] =
static_cast<long>(get_edge_numeric_attr(edge_id, capacity_attr));
710 original_edges.push_back({edge_id, u, v, e});
712 const auto source_index = get_vertex_index(id_to_bgl.at(source_id));
713 const auto target_index = get_vertex_index(id_to_bgl.at(target_id));
714 boost::successive_shortest_path_nonnegative_weights(flow_graph, source_index, target_index);
715 ResidualMap residual = boost::get(boost::edge_residual_capacity, flow_graph);
717 for (
auto [eit, eend] = boost::out_edges(source_index, flow_graph); eit != eend; ++eit) flow_value += capacity[*eit] - residual[*eit];
718 const long cost = boost::find_flow_cost(flow_graph);
720 result.flow = flow_value;
722 detail::fill_flow_views(original_edges, capacity, residual, result.edge_flows, result.edge_flows_by_id);
726template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
731template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
Attribute-bearing edge insertion helpers and attribute-oriented graph method definitions.
Graph wrapper around Boost Graph Library with Python-inspired helpers.
Definition graph.hpp:272
auto edmonds_karp_maximum_flow(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes a maximum flow using the Edmonds-Karp algorithm.
Definition flow.hpp:377
auto successive_shortest_path_nonnegative_weights(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Computes a max-flow min-cost result using successive shortest path.
Definition flow.hpp:671
auto max_flow_min_cost(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Convenience alias for the default max-flow min-cost wrapper.
Definition flow.hpp:732
auto max_flow_min_cost_successive_shortest_path(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Convenience alias for successive_shortest_path_nonnegative_weights().
Definition flow.hpp:727
auto minimum_cut(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes a minimum cut between source and target using the named capacity attribute.
Definition flow.hpp:482
auto maximum_flow(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes the maximum flow value and edge assignments using the named capacity attribute.
Definition flow.hpp:479
long push_relabel_maximum_flow(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Runs push-relabel and stages residual state for a later cycle_canceling() call. Any later graph mutat...
Definition flow.hpp:610
auto cycle_canceling(const std::string &weight_attr="weight") const
Runs cycle canceling on the previously cached residual network.
Definition flow.hpp:649
auto max_flow_min_cost_cycle_canceling(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Computes a max-flow min-cost result using cycle canceling.
Definition flow.hpp:549
auto push_relabel_maximum_flow_result(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes a maximum flow using push-relabel and returns edge assignments.
Definition flow.hpp:428
auto max_flow_min_cost(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight")
Deprecated free-function alias for G.max_flow_min_cost(...).
Definition flow.hpp:372
auto max_flow_min_cost_successive_shortest_path(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight")
Deprecated free-function alias for G.max_flow_min_cost_successive_shortest_path(.....
Definition flow.hpp:356
auto cycle_canceling(const GraphWrapper &G, const std::string &weight_attr="weight")
Deprecated free-function alias for G.cycle_canceling(weight_attr).
Definition flow.hpp:322
auto maximum_flow(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity")
Deprecated free-function alias for G.maximum_flow(...).
Definition flow.hpp:259
auto edmonds_karp_maximum_flow(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity")
Deprecated free-function alias for G.edmonds_karp_maximum_flow(...).
Definition flow.hpp:227
auto push_relabel_maximum_flow_result(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity")
Deprecated free-function alias for G.push_relabel_maximum_flow_result(...).
Definition flow.hpp:243
auto minimum_cut(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity")
Deprecated free-function alias for G.minimum_cut(...).
Definition flow.hpp:275
long push_relabel_maximum_flow(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight")
Deprecated free-function alias for G.push_relabel_maximum_flow(...).
Definition flow.hpp:309
auto max_flow_min_cost_cycle_canceling(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight")
Deprecated free-function alias for G.max_flow_min_cost_cycle_canceling(...).
Definition flow.hpp:292
auto successive_shortest_path_nonnegative_weights(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight")
Deprecated free-function alias for G.successive_shortest_path_nonnegative_weights(....
Definition flow.hpp:339
Precise edge_id-based multigraph operations and edge-aware attribute access.
Result of a maximum-flow computation.
Definition flow.hpp:46
Result of a min-cost max-flow computation.
Definition flow.hpp:74
Result of a minimum-cut computation.
Definition flow.hpp:207