1 //=======================================================================
2 // Copyright 2000 University of Notre Dame.
3 // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //=======================================================================
10 #ifndef BOOST_PUSH_RELABEL_MAX_FLOW_HPP
11 #define BOOST_PUSH_RELABEL_MAX_FLOW_HPP
13 #include <boost/config.hpp>
18 #include <algorithm> // for std::min and std::max
20 #include <boost/pending/queue.hpp>
21 #include <boost/limits.hpp>
22 #include <boost/graph/graph_concepts.hpp>
23 #include <boost/graph/named_function_params.hpp>
29 // This implementation is based on Goldberg's
30 // "On Implementing Push-Relabel Method for the Maximum Flow Problem"
31 // by B.V. Cherkassky and A.V. Goldberg, IPCO '95, pp. 157--171
32 // and on the h_prf.c and hi_pr.c code written by the above authors.
34 // This implements the highest-label version of the push-relabel method
35 // with the global relabeling and gap relabeling heuristics.
37 // The terms "rank", "distance", "height" are synonyms in
38 // Goldberg's implementation, paper and in the CLR. A "layer" is a
39 // group of vertices with the same distance. The vertices in each
40 // layer are categorized as active or inactive. An active vertex
41 // has positive excess flow and its distance is less than n (it is
44 template <class Vertex>
45 struct preflow_layer {
46 std::list<Vertex> active_vertices;
47 std::list<Vertex> inactive_vertices;
50 template <class Graph,
51 class EdgeCapacityMap, // integer value type
52 class ResidualCapacityEdgeMap,
54 class VertexIndexMap, // vertex_descriptor -> integer
59 typedef graph_traits<Graph> Traits;
60 typedef typename Traits::vertex_descriptor vertex_descriptor;
61 typedef typename Traits::edge_descriptor edge_descriptor;
62 typedef typename Traits::vertex_iterator vertex_iterator;
63 typedef typename Traits::out_edge_iterator out_edge_iterator;
64 typedef typename Traits::vertices_size_type vertices_size_type;
65 typedef typename Traits::edges_size_type edges_size_type;
67 typedef preflow_layer<vertex_descriptor> Layer;
68 typedef std::vector< Layer > LayerArray;
69 typedef typename LayerArray::iterator layer_iterator;
70 typedef typename LayerArray::size_type distance_size_type;
72 typedef color_traits<default_color_type> ColorTraits;
74 //=======================================================================
75 // Some helper predicates
77 inline bool is_admissible(vertex_descriptor u, vertex_descriptor v) {
78 return distance[u] == distance[v] + 1;
80 inline bool is_residual_edge(edge_descriptor a) {
81 return 0 < residual_capacity[a];
83 inline bool is_saturated(edge_descriptor a) {
84 return residual_capacity[a] == 0;
87 //=======================================================================
88 // Layer List Management Functions
90 typedef typename std::list<vertex_descriptor>::iterator list_iterator;
92 void add_to_active_list(vertex_descriptor u, Layer& layer) {
93 BOOST_USING_STD_MIN();
94 BOOST_USING_STD_MAX();
95 layer.active_vertices.push_front(u);
96 max_active = max BOOST_PREVENT_MACRO_SUBSTITUTION(distance[u], max_active);
97 min_active = min BOOST_PREVENT_MACRO_SUBSTITUTION(distance[u], min_active);
98 layer_list_ptr[u] = layer.active_vertices.begin();
100 void remove_from_active_list(vertex_descriptor u) {
101 layers[distance[u]].active_vertices.erase(layer_list_ptr[u]);
104 void add_to_inactive_list(vertex_descriptor u, Layer& layer) {
105 layer.inactive_vertices.push_front(u);
106 layer_list_ptr[u] = layer.inactive_vertices.begin();
108 void remove_from_inactive_list(vertex_descriptor u) {
109 layers[distance[u]].inactive_vertices.erase(layer_list_ptr[u]);
112 //=======================================================================
114 push_relabel(Graph& g_,
116 ResidualCapacityEdgeMap res,
118 vertex_descriptor src_,
119 vertex_descriptor sink_,
121 : g(g_), n(num_vertices(g_)), capacity(cap), src(src_), sink(sink_),
123 excess_flow(num_vertices(g_)),
124 current(num_vertices(g_), out_edges(*vertices(g_).first, g_).second),
125 distance(num_vertices(g_)),
126 color(num_vertices(g_)),
128 residual_capacity(res),
129 layers(num_vertices(g_)),
130 layer_list_ptr(num_vertices(g_),
131 layers.front().inactive_vertices.end()),
132 push_count(0), update_count(0), relabel_count(0),
133 gap_count(0), gap_node_count(0),
134 work_since_last_update(0)
136 vertex_iterator u_iter, u_end;
137 // Don't count the reverse edges
138 edges_size_type m = num_edges(g) / 2;
139 nm = alpha() * n + m;
141 // Initialize flow to zero which means initializing
142 // the residual capacity to equal the capacity.
143 out_edge_iterator ei, e_end;
144 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
145 for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) {
146 residual_capacity[*ei] = capacity[*ei];
149 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
150 vertex_descriptor u = *u_iter;
152 current[u] = out_edges(u, g).first;
155 bool overflow_detected = false;
156 FlowValue test_excess = 0;
158 out_edge_iterator a_iter, a_end;
159 for (tie(a_iter, a_end) = out_edges(src, g); a_iter != a_end; ++a_iter)
160 if (target(*a_iter, g) != src)
161 test_excess += residual_capacity[*a_iter];
162 if (test_excess > (std::numeric_limits<FlowValue>::max)())
163 overflow_detected = true;
165 if (overflow_detected)
166 excess_flow[src] = (std::numeric_limits<FlowValue>::max)();
168 excess_flow[src] = 0;
169 for (tie(a_iter, a_end) = out_edges(src, g);
170 a_iter != a_end; ++a_iter) {
171 edge_descriptor a = *a_iter;
172 if (target(a, g) != src) {
174 FlowValue delta = residual_capacity[a];
175 residual_capacity[a] -= delta;
176 residual_capacity[reverse_edge[a]] += delta;
177 excess_flow[target(a, g)] += delta;
181 max_distance = num_vertices(g) - 1;
185 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
186 vertex_descriptor u = *u_iter;
190 } else if (u == src && !overflow_detected)
195 if (excess_flow[u] > 0)
196 add_to_active_list(u, layers[1]);
197 else if (distance[u] < n)
198 add_to_inactive_list(u, layers[1]);
201 } // push_relabel constructor
203 //=======================================================================
204 // This is a breadth-first search over the residual graph
205 // (well, actually the reverse of the residual graph).
206 // Would be cool to have a graph view adaptor for hiding certain
207 // edges, like the saturated (non-residual) edges in this case.
208 // Goldberg's implementation abused "distance" for the coloring.
209 void global_distance_update()
211 BOOST_USING_STD_MAX();
213 vertex_iterator u_iter, u_end;
214 for (tie(u_iter,u_end) = vertices(g); u_iter != u_end; ++u_iter) {
215 color[*u_iter] = ColorTraits::white();
216 distance[*u_iter] = n;
218 color[sink] = ColorTraits::gray();
221 for (distance_size_type l = 0; l <= max_distance; ++l) {
222 layers[l].active_vertices.clear();
223 layers[l].inactive_vertices.clear();
226 max_distance = max_active = 0;
230 while (! Q.empty()) {
231 vertex_descriptor u = Q.top();
233 distance_size_type d_v = distance[u] + 1;
235 out_edge_iterator ai, a_end;
236 for (tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai) {
237 edge_descriptor a = *ai;
238 vertex_descriptor v = target(a, g);
239 if (color[v] == ColorTraits::white()
240 && is_residual_edge(reverse_edge[a])) {
242 color[v] = ColorTraits::gray();
243 current[v] = out_edges(v, g).first;
244 max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(d_v, max_distance);
246 if (excess_flow[v] > 0)
247 add_to_active_list(v, layers[d_v]);
249 add_to_inactive_list(v, layers[d_v]);
255 } // global_distance_update()
257 //=======================================================================
258 // This function is called "push" in Goldberg's h_prf implementation,
259 // but it is called "discharge" in the paper and in hi_pr.c.
260 void discharge(vertex_descriptor u)
262 assert(excess_flow[u] > 0);
264 out_edge_iterator ai, ai_end;
265 for (ai = current[u], ai_end = out_edges(u, g).second;
266 ai != ai_end; ++ai) {
267 edge_descriptor a = *ai;
268 if (is_residual_edge(a)) {
269 vertex_descriptor v = target(a, g);
270 if (is_admissible(u, v)) {
272 if (v != sink && excess_flow[v] == 0) {
273 remove_from_inactive_list(v);
274 add_to_active_list(v, layers[distance[v]]);
277 if (excess_flow[u] == 0)
281 } // for out_edges of i starting from current
283 Layer& layer = layers[distance[u]];
284 distance_size_type du = distance[u];
286 if (ai == ai_end) { // i must be relabeled
288 if (layer.active_vertices.empty()
289 && layer.inactive_vertices.empty())
291 if (distance[u] == n)
293 } else { // i is no longer active
295 add_to_inactive_list(u, layer);
301 //=======================================================================
302 // This corresponds to the "push" update operation of the paper,
303 // not the "push" function in Goldberg's h_prf.c implementation.
304 // The idea is to push the excess flow from from vertex u to v.
305 void push_flow(edge_descriptor u_v)
311 BOOST_USING_STD_MIN();
313 = min BOOST_PREVENT_MACRO_SUBSTITUTION(excess_flow[u], residual_capacity[u_v]);
315 residual_capacity[u_v] -= flow_delta;
316 residual_capacity[reverse_edge[u_v]] += flow_delta;
318 excess_flow[u] -= flow_delta;
319 excess_flow[v] += flow_delta;
322 //=======================================================================
323 // The main purpose of this routine is to set distance[v]
324 // to the smallest value allowed by the valid labeling constraints,
327 // distance[u] <= distance[v] + 1 for every residual edge (u,v)
329 distance_size_type relabel_distance(vertex_descriptor u)
331 BOOST_USING_STD_MAX();
333 work_since_last_update += beta();
335 distance_size_type min_distance = num_vertices(g);
336 distance[u] = min_distance;
338 // Examine the residual out-edges of vertex i, choosing the
339 // edge whose target vertex has the minimal distance.
340 out_edge_iterator ai, a_end, min_edge_iter;
341 for (tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai) {
342 ++work_since_last_update;
343 edge_descriptor a = *ai;
344 vertex_descriptor v = target(a, g);
345 if (is_residual_edge(a) && distance[v] < min_distance) {
346 min_distance = distance[v];
351 if (min_distance < n) {
352 distance[u] = min_distance; // this is the main action
353 current[u] = min_edge_iter;
354 max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(min_distance, max_distance);
357 } // relabel_distance()
359 //=======================================================================
360 // cleanup beyond the gap
361 void gap(distance_size_type empty_distance)
365 distance_size_type r; // distance of layer before the current layer
366 r = empty_distance - 1;
368 // Set the distance for the vertices beyond the gap to "infinity".
369 for (layer_iterator l = layers.begin() + empty_distance + 1;
370 l < layers.begin() + max_distance; ++l) {
372 for (i = l->inactive_vertices.begin();
373 i != l->inactive_vertices.end(); ++i) {
377 l->inactive_vertices.clear();
383 //=======================================================================
384 // This is the core part of the algorithm, "phase one".
385 FlowValue maximum_preflow()
387 work_since_last_update = 0;
389 while (max_active >= min_active) { // "main" loop
391 Layer& layer = layers[max_active];
392 list_iterator u_iter = layer.active_vertices.begin();
394 if (u_iter == layer.active_vertices.end())
397 vertex_descriptor u = *u_iter;
398 remove_from_active_list(u);
402 if (work_since_last_update * global_update_frequency() > nm) {
403 global_distance_update();
404 work_since_last_update = 0;
407 } // while (max_active >= min_active)
409 return excess_flow[sink];
410 } // maximum_preflow()
412 //=======================================================================
413 // remove excess flow, the "second phase"
414 // This does a DFS on the reverse flow graph of nodes with excess flow.
415 // If a cycle is found, cancel it.
416 // Return the nodes with excess flow in topological order.
418 // Unlike the prefl_to_flow() implementation, we use
419 // "color" instead of "distance" for the DFS labels
420 // "parent" instead of nl_prev for the DFS tree
421 // "topo_next" instead of nl_next for the topological ordering
422 void convert_preflow_to_flow()
424 vertex_iterator u_iter, u_end;
425 out_edge_iterator ai, a_end;
427 vertex_descriptor r, restart, u;
429 std::vector<vertex_descriptor> parent(n);
430 std::vector<vertex_descriptor> topo_next(n);
432 vertex_descriptor tos(parent[0]),
433 bos(parent[0]); // bogus initialization, just to avoid warning
434 bool bos_null = true;
437 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
438 for (tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end; ++ai)
439 if (target(*ai, g) == *u_iter)
440 residual_capacity[*ai] = capacity[*ai];
443 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
445 color[u] = ColorTraits::white();
447 current[u] = out_edges(u, g).first;
449 // eliminate flow cycles and topologically order the vertices
450 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
452 if (color[u] == ColorTraits::white()
453 && excess_flow[u] > 0
454 && u != src && u != sink ) {
456 color[r] = ColorTraits::gray();
458 for (; current[u] != out_edges(u, g).second; ++current[u]) {
459 edge_descriptor a = *current[u];
460 if (capacity[a] == 0 && is_residual_edge(a)) {
461 vertex_descriptor v = target(a, g);
462 if (color[v] == ColorTraits::white()) {
463 color[v] = ColorTraits::gray();
467 } else if (color[v] == ColorTraits::gray()) {
468 // find minimum flow on the cycle
469 FlowValue delta = residual_capacity[a];
471 BOOST_USING_STD_MIN();
472 delta = min BOOST_PREVENT_MACRO_SUBSTITUTION(delta, residual_capacity[*current[v]]);
476 v = target(*current[v], g);
478 // remove delta flow units
482 residual_capacity[a] -= delta;
483 residual_capacity[reverse_edge[a]] += delta;
489 // back-out of DFS to the first saturated edge
491 for (v = target(*current[u], g); v != u; v = target(a, g)){
493 if (color[v] == ColorTraits::white()
494 || is_saturated(a)) {
495 color[target(*current[v], g)] = ColorTraits::white();
496 if (color[v] != ColorTraits::white())
505 } // else if (color[v] == ColorTraits::gray())
506 } // if (capacity[a] == 0 ...
507 } // for out_edges(u, g) (though "u" changes during loop)
509 if (current[u] == out_edges(u, g).second) {
510 // scan of i is complete
511 color[u] = ColorTraits::black();
529 } // if (color[u] == white && excess_flow[u] > 0 & ...)
530 } // for all vertices in g
532 // return excess flows
533 // note that the sink is not on the stack
535 for (u = tos; u != bos; u = topo_next[u]) {
536 ai = out_edges(u, g).first;
537 while (excess_flow[u] > 0 && ai != out_edges(u, g).second) {
538 if (capacity[*ai] == 0 && is_residual_edge(*ai))
545 ai = out_edges(u, g).first;
546 while (excess_flow[u] > 0) {
547 if (capacity[*ai] == 0 && is_residual_edge(*ai))
553 } // convert_preflow_to_flow()
555 //=======================================================================
556 inline bool is_flow()
558 vertex_iterator u_iter, u_end;
559 out_edge_iterator ai, a_end;
561 // check edge flow values
562 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
563 for (tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end; ++ai) {
564 edge_descriptor a = *ai;
566 if ((residual_capacity[a] + residual_capacity[reverse_edge[a]]
567 != capacity[a] + capacity[reverse_edge[a]])
568 || (residual_capacity[a] < 0)
569 || (residual_capacity[reverse_edge[a]] < 0))
574 // check conservation
576 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
577 vertex_descriptor u = *u_iter;
578 if (u != src && u != sink) {
579 if (excess_flow[u] != 0)
582 for (tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai)
583 if (capacity[*ai] > 0)
584 sum -= capacity[*ai] - residual_capacity[*ai];
586 sum += residual_capacity[*ai];
588 if (excess_flow[u] != sum)
597 // check if mincut is saturated...
598 global_distance_update();
599 return distance[src] >= n;
602 void print_statistics(std::ostream& os) const {
603 os << "pushes: " << push_count << std::endl
604 << "relabels: " << relabel_count << std::endl
605 << "updates: " << update_count << std::endl
606 << "gaps: " << gap_count << std::endl
607 << "gap nodes: " << gap_node_count << std::endl
611 void print_flow_values(std::ostream& os) const {
612 os << "flow values" << std::endl;
613 vertex_iterator u_iter, u_end;
614 out_edge_iterator ei, e_end;
615 for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
616 for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
617 if (capacity[*ei] > 0)
618 os << *u_iter << " " << target(*ei, g) << " "
619 << (capacity[*ei] - residual_capacity[*ei]) << std::endl;
623 //=======================================================================
626 vertices_size_type n;
627 vertices_size_type nm;
628 EdgeCapacityMap capacity;
629 vertex_descriptor src;
630 vertex_descriptor sink;
631 VertexIndexMap index;
633 // will need to use random_access_property_map with these
634 std::vector< FlowValue > excess_flow;
635 std::vector< out_edge_iterator > current;
636 std::vector< distance_size_type > distance;
637 std::vector< default_color_type > color;
639 // Edge Property Maps that must be interior to the graph
640 ReverseEdgeMap reverse_edge;
641 ResidualCapacityEdgeMap residual_capacity;
644 std::vector< list_iterator > layer_list_ptr;
645 distance_size_type max_distance; // maximal distance
646 distance_size_type max_active; // maximal distance with active node
647 distance_size_type min_active; // minimal distance with active node
648 boost::queue<vertex_descriptor> Q;
650 // Statistics counters
657 inline double global_update_frequency() { return 0.5; }
658 inline vertices_size_type alpha() { return 6; }
659 inline long beta() { return 12; }
661 long work_since_last_update;
664 } // namespace detail
666 template <class Graph,
667 class CapacityEdgeMap, class ResidualCapacityEdgeMap,
668 class ReverseEdgeMap, class VertexIndexMap>
669 typename property_traits<CapacityEdgeMap>::value_type
670 push_relabel_max_flow
672 typename graph_traits<Graph>::vertex_descriptor src,
673 typename graph_traits<Graph>::vertex_descriptor sink,
674 CapacityEdgeMap cap, ResidualCapacityEdgeMap res,
675 ReverseEdgeMap rev, VertexIndexMap index_map)
677 typedef typename property_traits<CapacityEdgeMap>::value_type FlowValue;
679 detail::push_relabel<Graph, CapacityEdgeMap, ResidualCapacityEdgeMap,
680 ReverseEdgeMap, VertexIndexMap, FlowValue>
681 algo(g, cap, res, rev, src, sink, index_map);
683 FlowValue flow = algo.maximum_preflow();
685 algo.convert_preflow_to_flow();
687 assert(algo.is_flow());
688 assert(algo.is_optimal());
691 } // push_relabel_max_flow()
693 template <class Graph, class P, class T, class R>
694 typename detail::edge_capacity_value<Graph, P, T, R>::type
695 push_relabel_max_flow
697 typename graph_traits<Graph>::vertex_descriptor src,
698 typename graph_traits<Graph>::vertex_descriptor sink,
699 const bgl_named_params<P, T, R>& params)
701 return push_relabel_max_flow
703 choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
704 choose_pmap(get_param(params, edge_residual_capacity),
705 g, edge_residual_capacity),
706 choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
707 choose_const_pmap(get_param(params, vertex_index), g, vertex_index)
711 template <class Graph>
712 typename property_traits<
713 typename property_map<Graph, edge_capacity_t>::const_type
715 push_relabel_max_flow
717 typename graph_traits<Graph>::vertex_descriptor src,
718 typename graph_traits<Graph>::vertex_descriptor sink)
720 bgl_named_params<int, buffer_param_t> params(0); // bogus empty param
721 return push_relabel_max_flow(g, src, sink, params);
726 #endif // BOOST_PUSH_RELABEL_MAX_FLOW_HPP