Chris@16
|
1 //=======================================================================
|
Chris@16
|
2 // Copyright 2000 University of Notre Dame.
|
Chris@16
|
3 // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee
|
Chris@16
|
4 //
|
Chris@16
|
5 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
6 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 //=======================================================================
|
Chris@16
|
9
|
Chris@16
|
10 #ifndef BOOST_PUSH_RELABEL_MAX_FLOW_HPP
|
Chris@16
|
11 #define BOOST_PUSH_RELABEL_MAX_FLOW_HPP
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/config.hpp>
|
Chris@16
|
14 #include <boost/assert.hpp>
|
Chris@16
|
15 #include <vector>
|
Chris@16
|
16 #include <list>
|
Chris@16
|
17 #include <iosfwd>
|
Chris@16
|
18 #include <algorithm> // for std::min and std::max
|
Chris@16
|
19
|
Chris@16
|
20 #include <boost/pending/queue.hpp>
|
Chris@16
|
21 #include <boost/limits.hpp>
|
Chris@16
|
22 #include <boost/graph/graph_concepts.hpp>
|
Chris@16
|
23 #include <boost/graph/named_function_params.hpp>
|
Chris@16
|
24
|
Chris@16
|
25 namespace boost {
|
Chris@16
|
26
|
Chris@16
|
27 namespace detail {
|
Chris@16
|
28
|
Chris@16
|
29 // This implementation is based on Goldberg's
|
Chris@16
|
30 // "On Implementing Push-Relabel Method for the Maximum Flow Problem"
|
Chris@16
|
31 // by B.V. Cherkassky and A.V. Goldberg, IPCO '95, pp. 157--171
|
Chris@16
|
32 // and on the h_prf.c and hi_pr.c code written by the above authors.
|
Chris@16
|
33
|
Chris@16
|
34 // This implements the highest-label version of the push-relabel method
|
Chris@16
|
35 // with the global relabeling and gap relabeling heuristics.
|
Chris@16
|
36
|
Chris@16
|
37 // The terms "rank", "distance", "height" are synonyms in
|
Chris@16
|
38 // Goldberg's implementation, paper and in the CLR. A "layer" is a
|
Chris@16
|
39 // group of vertices with the same distance. The vertices in each
|
Chris@16
|
40 // layer are categorized as active or inactive. An active vertex
|
Chris@16
|
41 // has positive excess flow and its distance is less than n (it is
|
Chris@16
|
42 // not blocked).
|
Chris@16
|
43
|
Chris@16
|
44 template <class Vertex>
|
Chris@16
|
45 struct preflow_layer {
|
Chris@16
|
46 std::list<Vertex> active_vertices;
|
Chris@16
|
47 std::list<Vertex> inactive_vertices;
|
Chris@16
|
48 };
|
Chris@16
|
49
|
Chris@16
|
50 template <class Graph,
|
Chris@16
|
51 class EdgeCapacityMap, // integer value type
|
Chris@16
|
52 class ResidualCapacityEdgeMap,
|
Chris@16
|
53 class ReverseEdgeMap,
|
Chris@16
|
54 class VertexIndexMap, // vertex_descriptor -> integer
|
Chris@16
|
55 class FlowValue>
|
Chris@16
|
56 class push_relabel
|
Chris@16
|
57 {
|
Chris@16
|
58 public:
|
Chris@16
|
59 typedef graph_traits<Graph> Traits;
|
Chris@16
|
60 typedef typename Traits::vertex_descriptor vertex_descriptor;
|
Chris@16
|
61 typedef typename Traits::edge_descriptor edge_descriptor;
|
Chris@16
|
62 typedef typename Traits::vertex_iterator vertex_iterator;
|
Chris@16
|
63 typedef typename Traits::out_edge_iterator out_edge_iterator;
|
Chris@16
|
64 typedef typename Traits::vertices_size_type vertices_size_type;
|
Chris@16
|
65 typedef typename Traits::edges_size_type edges_size_type;
|
Chris@16
|
66
|
Chris@16
|
67 typedef preflow_layer<vertex_descriptor> Layer;
|
Chris@16
|
68 typedef std::vector< Layer > LayerArray;
|
Chris@16
|
69 typedef typename LayerArray::iterator layer_iterator;
|
Chris@16
|
70 typedef typename LayerArray::size_type distance_size_type;
|
Chris@16
|
71
|
Chris@16
|
72 typedef color_traits<default_color_type> ColorTraits;
|
Chris@16
|
73
|
Chris@16
|
74 //=======================================================================
|
Chris@16
|
75 // Some helper predicates
|
Chris@16
|
76
|
Chris@16
|
77 inline bool is_admissible(vertex_descriptor u, vertex_descriptor v) {
|
Chris@16
|
78 return get(distance, u) == get(distance, v) + 1;
|
Chris@16
|
79 }
|
Chris@16
|
80 inline bool is_residual_edge(edge_descriptor a) {
|
Chris@16
|
81 return 0 < get(residual_capacity, a);
|
Chris@16
|
82 }
|
Chris@16
|
83 inline bool is_saturated(edge_descriptor a) {
|
Chris@16
|
84 return get(residual_capacity, a) == 0;
|
Chris@16
|
85 }
|
Chris@16
|
86
|
Chris@16
|
87 //=======================================================================
|
Chris@16
|
88 // Layer List Management Functions
|
Chris@16
|
89
|
Chris@16
|
90 typedef typename std::list<vertex_descriptor>::iterator list_iterator;
|
Chris@16
|
91
|
Chris@16
|
92 void add_to_active_list(vertex_descriptor u, Layer& layer) {
|
Chris@16
|
93 BOOST_USING_STD_MIN();
|
Chris@16
|
94 BOOST_USING_STD_MAX();
|
Chris@16
|
95 layer.active_vertices.push_front(u);
|
Chris@16
|
96 max_active = max BOOST_PREVENT_MACRO_SUBSTITUTION(get(distance, u), max_active);
|
Chris@16
|
97 min_active = min BOOST_PREVENT_MACRO_SUBSTITUTION(get(distance, u), min_active);
|
Chris@16
|
98 layer_list_ptr[u] = layer.active_vertices.begin();
|
Chris@16
|
99 }
|
Chris@16
|
100 void remove_from_active_list(vertex_descriptor u) {
|
Chris@16
|
101 layers[get(distance, u)].active_vertices.erase(layer_list_ptr[u]);
|
Chris@16
|
102 }
|
Chris@16
|
103
|
Chris@16
|
104 void add_to_inactive_list(vertex_descriptor u, Layer& layer) {
|
Chris@16
|
105 layer.inactive_vertices.push_front(u);
|
Chris@16
|
106 layer_list_ptr[u] = layer.inactive_vertices.begin();
|
Chris@16
|
107 }
|
Chris@16
|
108 void remove_from_inactive_list(vertex_descriptor u) {
|
Chris@16
|
109 layers[get(distance, u)].inactive_vertices.erase(layer_list_ptr[u]);
|
Chris@16
|
110 }
|
Chris@16
|
111
|
Chris@16
|
112 //=======================================================================
|
Chris@16
|
113 // initialization
|
Chris@16
|
114 push_relabel(Graph& g_,
|
Chris@16
|
115 EdgeCapacityMap cap,
|
Chris@16
|
116 ResidualCapacityEdgeMap res,
|
Chris@16
|
117 ReverseEdgeMap rev,
|
Chris@16
|
118 vertex_descriptor src_,
|
Chris@16
|
119 vertex_descriptor sink_,
|
Chris@16
|
120 VertexIndexMap idx)
|
Chris@16
|
121 : g(g_), n(num_vertices(g_)), capacity(cap), src(src_), sink(sink_),
|
Chris@16
|
122 index(idx),
|
Chris@16
|
123 excess_flow_data(num_vertices(g_)),
|
Chris@16
|
124 excess_flow(excess_flow_data.begin(), idx),
|
Chris@16
|
125 current_data(num_vertices(g_), out_edges(*vertices(g_).first, g_)),
|
Chris@16
|
126 current(current_data.begin(), idx),
|
Chris@16
|
127 distance_data(num_vertices(g_)),
|
Chris@16
|
128 distance(distance_data.begin(), idx),
|
Chris@16
|
129 color_data(num_vertices(g_)),
|
Chris@16
|
130 color(color_data.begin(), idx),
|
Chris@16
|
131 reverse_edge(rev),
|
Chris@16
|
132 residual_capacity(res),
|
Chris@16
|
133 layers(num_vertices(g_)),
|
Chris@16
|
134 layer_list_ptr_data(num_vertices(g_),
|
Chris@16
|
135 layers.front().inactive_vertices.end()),
|
Chris@16
|
136 layer_list_ptr(layer_list_ptr_data.begin(), idx),
|
Chris@16
|
137 push_count(0), update_count(0), relabel_count(0),
|
Chris@16
|
138 gap_count(0), gap_node_count(0),
|
Chris@16
|
139 work_since_last_update(0)
|
Chris@16
|
140 {
|
Chris@16
|
141 vertex_iterator u_iter, u_end;
|
Chris@16
|
142 // Don't count the reverse edges
|
Chris@16
|
143 edges_size_type m = num_edges(g) / 2;
|
Chris@16
|
144 nm = alpha() * n + m;
|
Chris@16
|
145
|
Chris@16
|
146 // Initialize flow to zero which means initializing
|
Chris@16
|
147 // the residual capacity to equal the capacity.
|
Chris@16
|
148 out_edge_iterator ei, e_end;
|
Chris@16
|
149 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
|
Chris@16
|
150 for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) {
|
Chris@16
|
151 put(residual_capacity, *ei, get(capacity, *ei));
|
Chris@16
|
152 }
|
Chris@16
|
153
|
Chris@16
|
154 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
|
Chris@16
|
155 vertex_descriptor u = *u_iter;
|
Chris@16
|
156 put(excess_flow, u, 0);
|
Chris@16
|
157 current[u] = out_edges(u, g);
|
Chris@16
|
158 }
|
Chris@16
|
159
|
Chris@16
|
160 bool overflow_detected = false;
|
Chris@16
|
161 FlowValue test_excess = 0;
|
Chris@16
|
162
|
Chris@16
|
163 out_edge_iterator a_iter, a_end;
|
Chris@16
|
164 for (boost::tie(a_iter, a_end) = out_edges(src, g); a_iter != a_end; ++a_iter)
|
Chris@16
|
165 if (target(*a_iter, g) != src)
|
Chris@16
|
166 test_excess += get(residual_capacity, *a_iter);
|
Chris@16
|
167 if (test_excess > (std::numeric_limits<FlowValue>::max)())
|
Chris@16
|
168 overflow_detected = true;
|
Chris@16
|
169
|
Chris@16
|
170 if (overflow_detected)
|
Chris@16
|
171 put(excess_flow, src, (std::numeric_limits<FlowValue>::max)());
|
Chris@16
|
172 else {
|
Chris@16
|
173 put(excess_flow, src, 0);
|
Chris@16
|
174 for (boost::tie(a_iter, a_end) = out_edges(src, g);
|
Chris@16
|
175 a_iter != a_end; ++a_iter) {
|
Chris@16
|
176 edge_descriptor a = *a_iter;
|
Chris@16
|
177 vertex_descriptor tgt = target(a, g);
|
Chris@16
|
178 if (tgt != src) {
|
Chris@16
|
179 ++push_count;
|
Chris@16
|
180 FlowValue delta = get(residual_capacity, a);
|
Chris@16
|
181 put(residual_capacity, a, get(residual_capacity, a) - delta);
|
Chris@16
|
182 edge_descriptor rev = get(reverse_edge, a);
|
Chris@16
|
183 put(residual_capacity, rev, get(residual_capacity, rev) + delta);
|
Chris@16
|
184 put(excess_flow, tgt, get(excess_flow, tgt) + delta);
|
Chris@16
|
185 }
|
Chris@16
|
186 }
|
Chris@16
|
187 }
|
Chris@16
|
188 max_distance = num_vertices(g) - 1;
|
Chris@16
|
189 max_active = 0;
|
Chris@16
|
190 min_active = n;
|
Chris@16
|
191
|
Chris@16
|
192 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
|
Chris@16
|
193 vertex_descriptor u = *u_iter;
|
Chris@16
|
194 if (u == sink) {
|
Chris@16
|
195 put(distance, u, 0);
|
Chris@16
|
196 continue;
|
Chris@16
|
197 } else if (u == src && !overflow_detected)
|
Chris@16
|
198 put(distance, u, n);
|
Chris@16
|
199 else
|
Chris@16
|
200 put(distance, u, 1);
|
Chris@16
|
201
|
Chris@16
|
202 if (get(excess_flow, u) > 0)
|
Chris@16
|
203 add_to_active_list(u, layers[1]);
|
Chris@16
|
204 else if (get(distance, u) < n)
|
Chris@16
|
205 add_to_inactive_list(u, layers[1]);
|
Chris@16
|
206 }
|
Chris@16
|
207
|
Chris@16
|
208 } // push_relabel constructor
|
Chris@16
|
209
|
Chris@16
|
210 //=======================================================================
|
Chris@16
|
211 // This is a breadth-first search over the residual graph
|
Chris@16
|
212 // (well, actually the reverse of the residual graph).
|
Chris@16
|
213 // Would be cool to have a graph view adaptor for hiding certain
|
Chris@16
|
214 // edges, like the saturated (non-residual) edges in this case.
|
Chris@16
|
215 // Goldberg's implementation abused "distance" for the coloring.
|
Chris@16
|
216 void global_distance_update()
|
Chris@16
|
217 {
|
Chris@16
|
218 BOOST_USING_STD_MAX();
|
Chris@16
|
219 ++update_count;
|
Chris@16
|
220 vertex_iterator u_iter, u_end;
|
Chris@16
|
221 for (boost::tie(u_iter,u_end) = vertices(g); u_iter != u_end; ++u_iter) {
|
Chris@16
|
222 put(color, *u_iter, ColorTraits::white());
|
Chris@16
|
223 put(distance, *u_iter, n);
|
Chris@16
|
224 }
|
Chris@16
|
225 put(color, sink, ColorTraits::gray());
|
Chris@16
|
226 put(distance, sink, 0);
|
Chris@16
|
227
|
Chris@16
|
228 for (distance_size_type l = 0; l <= max_distance; ++l) {
|
Chris@16
|
229 layers[l].active_vertices.clear();
|
Chris@16
|
230 layers[l].inactive_vertices.clear();
|
Chris@16
|
231 }
|
Chris@16
|
232
|
Chris@16
|
233 max_distance = max_active = 0;
|
Chris@16
|
234 min_active = n;
|
Chris@16
|
235
|
Chris@16
|
236 Q.push(sink);
|
Chris@16
|
237 while (! Q.empty()) {
|
Chris@16
|
238 vertex_descriptor u = Q.top();
|
Chris@16
|
239 Q.pop();
|
Chris@16
|
240 distance_size_type d_v = get(distance, u) + 1;
|
Chris@16
|
241
|
Chris@16
|
242 out_edge_iterator ai, a_end;
|
Chris@16
|
243 for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai) {
|
Chris@16
|
244 edge_descriptor a = *ai;
|
Chris@16
|
245 vertex_descriptor v = target(a, g);
|
Chris@16
|
246 if (get(color, v) == ColorTraits::white()
|
Chris@16
|
247 && is_residual_edge(get(reverse_edge, a))) {
|
Chris@16
|
248 put(distance, v, d_v);
|
Chris@16
|
249 put(color, v, ColorTraits::gray());
|
Chris@16
|
250 current[v] = out_edges(v, g);
|
Chris@16
|
251 max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(d_v, max_distance);
|
Chris@16
|
252
|
Chris@16
|
253 if (get(excess_flow, v) > 0)
|
Chris@16
|
254 add_to_active_list(v, layers[d_v]);
|
Chris@16
|
255 else
|
Chris@16
|
256 add_to_inactive_list(v, layers[d_v]);
|
Chris@16
|
257
|
Chris@16
|
258 Q.push(v);
|
Chris@16
|
259 }
|
Chris@16
|
260 }
|
Chris@16
|
261 }
|
Chris@16
|
262 } // global_distance_update()
|
Chris@16
|
263
|
Chris@16
|
264 //=======================================================================
|
Chris@16
|
265 // This function is called "push" in Goldberg's h_prf implementation,
|
Chris@16
|
266 // but it is called "discharge" in the paper and in hi_pr.c.
|
Chris@16
|
267 void discharge(vertex_descriptor u)
|
Chris@16
|
268 {
|
Chris@16
|
269 BOOST_ASSERT(get(excess_flow, u) > 0);
|
Chris@16
|
270 while (1) {
|
Chris@16
|
271 out_edge_iterator ai, ai_end;
|
Chris@16
|
272 for (boost::tie(ai, ai_end) = current[u]; ai != ai_end; ++ai) {
|
Chris@16
|
273 edge_descriptor a = *ai;
|
Chris@16
|
274 if (is_residual_edge(a)) {
|
Chris@16
|
275 vertex_descriptor v = target(a, g);
|
Chris@16
|
276 if (is_admissible(u, v)) {
|
Chris@16
|
277 ++push_count;
|
Chris@16
|
278 if (v != sink && get(excess_flow, v) == 0) {
|
Chris@16
|
279 remove_from_inactive_list(v);
|
Chris@16
|
280 add_to_active_list(v, layers[get(distance, v)]);
|
Chris@16
|
281 }
|
Chris@16
|
282 push_flow(a);
|
Chris@16
|
283 if (get(excess_flow, u) == 0)
|
Chris@16
|
284 break;
|
Chris@16
|
285 }
|
Chris@16
|
286 }
|
Chris@16
|
287 } // for out_edges of i starting from current
|
Chris@16
|
288
|
Chris@16
|
289 Layer& layer = layers[get(distance, u)];
|
Chris@16
|
290 distance_size_type du = get(distance, u);
|
Chris@16
|
291
|
Chris@16
|
292 if (ai == ai_end) { // i must be relabeled
|
Chris@16
|
293 relabel_distance(u);
|
Chris@16
|
294 if (layer.active_vertices.empty()
|
Chris@16
|
295 && layer.inactive_vertices.empty())
|
Chris@16
|
296 gap(du);
|
Chris@16
|
297 if (get(distance, u) == n)
|
Chris@16
|
298 break;
|
Chris@16
|
299 } else { // i is no longer active
|
Chris@16
|
300 current[u].first = ai;
|
Chris@16
|
301 add_to_inactive_list(u, layer);
|
Chris@16
|
302 break;
|
Chris@16
|
303 }
|
Chris@16
|
304 } // while (1)
|
Chris@16
|
305 } // discharge()
|
Chris@16
|
306
|
Chris@16
|
307 //=======================================================================
|
Chris@16
|
308 // This corresponds to the "push" update operation of the paper,
|
Chris@16
|
309 // not the "push" function in Goldberg's h_prf.c implementation.
|
Chris@16
|
310 // The idea is to push the excess flow from from vertex u to v.
|
Chris@16
|
311 void push_flow(edge_descriptor u_v)
|
Chris@16
|
312 {
|
Chris@16
|
313 vertex_descriptor
|
Chris@16
|
314 u = source(u_v, g),
|
Chris@16
|
315 v = target(u_v, g);
|
Chris@16
|
316
|
Chris@16
|
317 BOOST_USING_STD_MIN();
|
Chris@16
|
318 FlowValue flow_delta
|
Chris@16
|
319 = min BOOST_PREVENT_MACRO_SUBSTITUTION(get(excess_flow, u), get(residual_capacity, u_v));
|
Chris@16
|
320
|
Chris@16
|
321 put(residual_capacity, u_v, get(residual_capacity, u_v) - flow_delta);
|
Chris@16
|
322 edge_descriptor rev = get(reverse_edge, u_v);
|
Chris@16
|
323 put(residual_capacity, rev, get(residual_capacity, rev) + flow_delta);
|
Chris@16
|
324
|
Chris@16
|
325 put(excess_flow, u, get(excess_flow, u) - flow_delta);
|
Chris@16
|
326 put(excess_flow, v, get(excess_flow, v) + flow_delta);
|
Chris@16
|
327 } // push_flow()
|
Chris@16
|
328
|
Chris@16
|
329 //=======================================================================
|
Chris@16
|
330 // The main purpose of this routine is to set distance[v]
|
Chris@16
|
331 // to the smallest value allowed by the valid labeling constraints,
|
Chris@16
|
332 // which are:
|
Chris@16
|
333 // distance[t] = 0
|
Chris@16
|
334 // distance[u] <= distance[v] + 1 for every residual edge (u,v)
|
Chris@16
|
335 //
|
Chris@16
|
336 distance_size_type relabel_distance(vertex_descriptor u)
|
Chris@16
|
337 {
|
Chris@16
|
338 BOOST_USING_STD_MAX();
|
Chris@16
|
339 ++relabel_count;
|
Chris@16
|
340 work_since_last_update += beta();
|
Chris@16
|
341
|
Chris@16
|
342 distance_size_type min_distance = num_vertices(g);
|
Chris@16
|
343 put(distance, u, min_distance);
|
Chris@16
|
344
|
Chris@16
|
345 // Examine the residual out-edges of vertex i, choosing the
|
Chris@16
|
346 // edge whose target vertex has the minimal distance.
|
Chris@16
|
347 out_edge_iterator ai, a_end, min_edge_iter;
|
Chris@16
|
348 for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai) {
|
Chris@16
|
349 ++work_since_last_update;
|
Chris@16
|
350 edge_descriptor a = *ai;
|
Chris@16
|
351 vertex_descriptor v = target(a, g);
|
Chris@16
|
352 if (is_residual_edge(a) && get(distance, v) < min_distance) {
|
Chris@16
|
353 min_distance = get(distance, v);
|
Chris@16
|
354 min_edge_iter = ai;
|
Chris@16
|
355 }
|
Chris@16
|
356 }
|
Chris@16
|
357 ++min_distance;
|
Chris@16
|
358 if (min_distance < n) {
|
Chris@16
|
359 put(distance, u, min_distance); // this is the main action
|
Chris@16
|
360 current[u].first = min_edge_iter;
|
Chris@16
|
361 max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(min_distance, max_distance);
|
Chris@16
|
362 }
|
Chris@16
|
363 return min_distance;
|
Chris@16
|
364 } // relabel_distance()
|
Chris@16
|
365
|
Chris@16
|
366 //=======================================================================
|
Chris@16
|
367 // cleanup beyond the gap
|
Chris@16
|
368 void gap(distance_size_type empty_distance)
|
Chris@16
|
369 {
|
Chris@16
|
370 ++gap_count;
|
Chris@16
|
371
|
Chris@16
|
372 distance_size_type r; // distance of layer before the current layer
|
Chris@16
|
373 r = empty_distance - 1;
|
Chris@16
|
374
|
Chris@16
|
375 // Set the distance for the vertices beyond the gap to "infinity".
|
Chris@16
|
376 for (layer_iterator l = layers.begin() + empty_distance + 1;
|
Chris@16
|
377 l < layers.begin() + max_distance; ++l) {
|
Chris@16
|
378 list_iterator i;
|
Chris@16
|
379 for (i = l->inactive_vertices.begin();
|
Chris@16
|
380 i != l->inactive_vertices.end(); ++i) {
|
Chris@16
|
381 put(distance, *i, n);
|
Chris@16
|
382 ++gap_node_count;
|
Chris@16
|
383 }
|
Chris@16
|
384 l->inactive_vertices.clear();
|
Chris@16
|
385 }
|
Chris@16
|
386 max_distance = r;
|
Chris@16
|
387 max_active = r;
|
Chris@16
|
388 }
|
Chris@16
|
389
|
Chris@16
|
390 //=======================================================================
|
Chris@16
|
391 // This is the core part of the algorithm, "phase one".
|
Chris@16
|
392 FlowValue maximum_preflow()
|
Chris@16
|
393 {
|
Chris@16
|
394 work_since_last_update = 0;
|
Chris@16
|
395
|
Chris@16
|
396 while (max_active >= min_active) { // "main" loop
|
Chris@16
|
397
|
Chris@16
|
398 Layer& layer = layers[max_active];
|
Chris@16
|
399 list_iterator u_iter = layer.active_vertices.begin();
|
Chris@16
|
400
|
Chris@16
|
401 if (u_iter == layer.active_vertices.end())
|
Chris@16
|
402 --max_active;
|
Chris@16
|
403 else {
|
Chris@16
|
404 vertex_descriptor u = *u_iter;
|
Chris@16
|
405 remove_from_active_list(u);
|
Chris@16
|
406
|
Chris@16
|
407 discharge(u);
|
Chris@16
|
408
|
Chris@16
|
409 if (work_since_last_update * global_update_frequency() > nm) {
|
Chris@16
|
410 global_distance_update();
|
Chris@16
|
411 work_since_last_update = 0;
|
Chris@16
|
412 }
|
Chris@16
|
413 }
|
Chris@16
|
414 } // while (max_active >= min_active)
|
Chris@16
|
415
|
Chris@16
|
416 return get(excess_flow, sink);
|
Chris@16
|
417 } // maximum_preflow()
|
Chris@16
|
418
|
Chris@16
|
419 //=======================================================================
|
Chris@16
|
420 // remove excess flow, the "second phase"
|
Chris@16
|
421 // This does a DFS on the reverse flow graph of nodes with excess flow.
|
Chris@16
|
422 // If a cycle is found, cancel it.
|
Chris@16
|
423 // Return the nodes with excess flow in topological order.
|
Chris@16
|
424 //
|
Chris@16
|
425 // Unlike the prefl_to_flow() implementation, we use
|
Chris@16
|
426 // "color" instead of "distance" for the DFS labels
|
Chris@16
|
427 // "parent" instead of nl_prev for the DFS tree
|
Chris@16
|
428 // "topo_next" instead of nl_next for the topological ordering
|
Chris@16
|
429 void convert_preflow_to_flow()
|
Chris@16
|
430 {
|
Chris@16
|
431 vertex_iterator u_iter, u_end;
|
Chris@16
|
432 out_edge_iterator ai, a_end;
|
Chris@16
|
433
|
Chris@16
|
434 vertex_descriptor r, restart, u;
|
Chris@16
|
435
|
Chris@16
|
436 std::vector<vertex_descriptor> parent(n);
|
Chris@16
|
437 std::vector<vertex_descriptor> topo_next(n);
|
Chris@16
|
438
|
Chris@16
|
439 vertex_descriptor tos(parent[0]),
|
Chris@16
|
440 bos(parent[0]); // bogus initialization, just to avoid warning
|
Chris@16
|
441 bool bos_null = true;
|
Chris@16
|
442
|
Chris@16
|
443 // handle self-loops
|
Chris@16
|
444 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
|
Chris@16
|
445 for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end; ++ai)
|
Chris@16
|
446 if (target(*ai, g) == *u_iter)
|
Chris@16
|
447 put(residual_capacity, *ai, get(capacity, *ai));
|
Chris@16
|
448
|
Chris@16
|
449 // initialize
|
Chris@16
|
450 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
|
Chris@16
|
451 u = *u_iter;
|
Chris@16
|
452 put(color, u, ColorTraits::white());
|
Chris@16
|
453 parent[get(index, u)] = u;
|
Chris@16
|
454 current[u] = out_edges(u, g);
|
Chris@16
|
455 }
|
Chris@16
|
456 // eliminate flow cycles and topologically order the vertices
|
Chris@16
|
457 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
|
Chris@16
|
458 u = *u_iter;
|
Chris@16
|
459 if (get(color, u) == ColorTraits::white()
|
Chris@16
|
460 && get(excess_flow, u) > 0
|
Chris@16
|
461 && u != src && u != sink ) {
|
Chris@16
|
462 r = u;
|
Chris@16
|
463 put(color, r, ColorTraits::gray());
|
Chris@16
|
464 while (1) {
|
Chris@16
|
465 for (; current[u].first != current[u].second; ++current[u].first) {
|
Chris@16
|
466 edge_descriptor a = *current[u].first;
|
Chris@16
|
467 if (get(capacity, a) == 0 && is_residual_edge(a)) {
|
Chris@16
|
468 vertex_descriptor v = target(a, g);
|
Chris@16
|
469 if (get(color, v) == ColorTraits::white()) {
|
Chris@16
|
470 put(color, v, ColorTraits::gray());
|
Chris@16
|
471 parent[get(index, v)] = u;
|
Chris@16
|
472 u = v;
|
Chris@16
|
473 break;
|
Chris@16
|
474 } else if (get(color, v) == ColorTraits::gray()) {
|
Chris@16
|
475 // find minimum flow on the cycle
|
Chris@16
|
476 FlowValue delta = get(residual_capacity, a);
|
Chris@16
|
477 while (1) {
|
Chris@16
|
478 BOOST_USING_STD_MIN();
|
Chris@16
|
479 delta = min BOOST_PREVENT_MACRO_SUBSTITUTION(delta, get(residual_capacity, *current[v].first));
|
Chris@16
|
480 if (v == u)
|
Chris@16
|
481 break;
|
Chris@16
|
482 else
|
Chris@16
|
483 v = target(*current[v].first, g);
|
Chris@16
|
484 }
|
Chris@16
|
485 // remove delta flow units
|
Chris@16
|
486 v = u;
|
Chris@16
|
487 while (1) {
|
Chris@16
|
488 a = *current[v].first;
|
Chris@16
|
489 put(residual_capacity, a, get(residual_capacity, a) - delta);
|
Chris@16
|
490 edge_descriptor rev = get(reverse_edge, a);
|
Chris@16
|
491 put(residual_capacity, rev, get(residual_capacity, rev) + delta);
|
Chris@16
|
492 v = target(a, g);
|
Chris@16
|
493 if (v == u)
|
Chris@16
|
494 break;
|
Chris@16
|
495 }
|
Chris@16
|
496
|
Chris@16
|
497 // back-out of DFS to the first saturated edge
|
Chris@16
|
498 restart = u;
|
Chris@16
|
499 for (v = target(*current[u].first, g); v != u; v = target(a, g)){
|
Chris@16
|
500 a = *current[v].first;
|
Chris@16
|
501 if (get(color, v) == ColorTraits::white()
|
Chris@16
|
502 || is_saturated(a)) {
|
Chris@16
|
503 put(color, target(*current[v].first, g), ColorTraits::white());
|
Chris@16
|
504 if (get(color, v) != ColorTraits::white())
|
Chris@16
|
505 restart = v;
|
Chris@16
|
506 }
|
Chris@16
|
507 }
|
Chris@16
|
508 if (restart != u) {
|
Chris@16
|
509 u = restart;
|
Chris@16
|
510 ++current[u].first;
|
Chris@16
|
511 break;
|
Chris@16
|
512 }
|
Chris@16
|
513 } // else if (color[v] == ColorTraits::gray())
|
Chris@16
|
514 } // if (get(capacity, a) == 0 ...
|
Chris@16
|
515 } // for out_edges(u, g) (though "u" changes during loop)
|
Chris@16
|
516
|
Chris@16
|
517 if ( current[u].first == current[u].second ) {
|
Chris@16
|
518 // scan of i is complete
|
Chris@16
|
519 put(color, u, ColorTraits::black());
|
Chris@16
|
520 if (u != src) {
|
Chris@16
|
521 if (bos_null) {
|
Chris@16
|
522 bos = u;
|
Chris@16
|
523 bos_null = false;
|
Chris@16
|
524 tos = u;
|
Chris@16
|
525 } else {
|
Chris@16
|
526 topo_next[get(index, u)] = tos;
|
Chris@16
|
527 tos = u;
|
Chris@16
|
528 }
|
Chris@16
|
529 }
|
Chris@16
|
530 if (u != r) {
|
Chris@16
|
531 u = parent[get(index, u)];
|
Chris@16
|
532 ++current[u].first;
|
Chris@16
|
533 } else
|
Chris@16
|
534 break;
|
Chris@16
|
535 }
|
Chris@16
|
536 } // while (1)
|
Chris@16
|
537 } // if (color[u] == white && excess_flow[u] > 0 & ...)
|
Chris@16
|
538 } // for all vertices in g
|
Chris@16
|
539
|
Chris@16
|
540 // return excess flows
|
Chris@16
|
541 // note that the sink is not on the stack
|
Chris@16
|
542 if (! bos_null) {
|
Chris@16
|
543 for (u = tos; u != bos; u = topo_next[get(index, u)]) {
|
Chris@16
|
544 boost::tie(ai, a_end) = out_edges(u, g);
|
Chris@16
|
545 while (get(excess_flow, u) > 0 && ai != a_end) {
|
Chris@16
|
546 if (get(capacity, *ai) == 0 && is_residual_edge(*ai))
|
Chris@16
|
547 push_flow(*ai);
|
Chris@16
|
548 ++ai;
|
Chris@16
|
549 }
|
Chris@16
|
550 }
|
Chris@16
|
551 // do the bottom
|
Chris@16
|
552 u = bos;
|
Chris@16
|
553 boost::tie(ai, a_end) = out_edges(u, g);
|
Chris@16
|
554 while (get(excess_flow, u) > 0 && ai != a_end) {
|
Chris@16
|
555 if (get(capacity, *ai) == 0 && is_residual_edge(*ai))
|
Chris@16
|
556 push_flow(*ai);
|
Chris@16
|
557 ++ai;
|
Chris@16
|
558 }
|
Chris@16
|
559 }
|
Chris@16
|
560
|
Chris@16
|
561 } // convert_preflow_to_flow()
|
Chris@16
|
562
|
Chris@16
|
563 //=======================================================================
|
Chris@16
|
564 inline bool is_flow()
|
Chris@16
|
565 {
|
Chris@16
|
566 vertex_iterator u_iter, u_end;
|
Chris@16
|
567 out_edge_iterator ai, a_end;
|
Chris@16
|
568
|
Chris@16
|
569 // check edge flow values
|
Chris@16
|
570 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
|
Chris@16
|
571 for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end; ++ai) {
|
Chris@16
|
572 edge_descriptor a = *ai;
|
Chris@16
|
573 if (get(capacity, a) > 0)
|
Chris@16
|
574 if ((get(residual_capacity, a) + get(residual_capacity, get(reverse_edge, a))
|
Chris@16
|
575 != get(capacity, a) + get(capacity, get(reverse_edge, a)))
|
Chris@16
|
576 || (get(residual_capacity, a) < 0)
|
Chris@16
|
577 || (get(residual_capacity, get(reverse_edge, a)) < 0))
|
Chris@16
|
578 return false;
|
Chris@16
|
579 }
|
Chris@16
|
580 }
|
Chris@16
|
581
|
Chris@16
|
582 // check conservation
|
Chris@16
|
583 FlowValue sum;
|
Chris@16
|
584 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
|
Chris@16
|
585 vertex_descriptor u = *u_iter;
|
Chris@16
|
586 if (u != src && u != sink) {
|
Chris@16
|
587 if (get(excess_flow, u) != 0)
|
Chris@16
|
588 return false;
|
Chris@16
|
589 sum = 0;
|
Chris@16
|
590 for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai)
|
Chris@16
|
591 if (get(capacity, *ai) > 0)
|
Chris@16
|
592 sum -= get(capacity, *ai) - get(residual_capacity, *ai);
|
Chris@16
|
593 else
|
Chris@16
|
594 sum += get(residual_capacity, *ai);
|
Chris@16
|
595
|
Chris@16
|
596 if (get(excess_flow, u) != sum)
|
Chris@16
|
597 return false;
|
Chris@16
|
598 }
|
Chris@16
|
599 }
|
Chris@16
|
600
|
Chris@16
|
601 return true;
|
Chris@16
|
602 } // is_flow()
|
Chris@16
|
603
|
Chris@16
|
604 bool is_optimal() {
|
Chris@16
|
605 // check if mincut is saturated...
|
Chris@16
|
606 global_distance_update();
|
Chris@16
|
607 return get(distance, src) >= n;
|
Chris@16
|
608 }
|
Chris@16
|
609
|
Chris@16
|
610 void print_statistics(std::ostream& os) const {
|
Chris@16
|
611 os << "pushes: " << push_count << std::endl
|
Chris@16
|
612 << "relabels: " << relabel_count << std::endl
|
Chris@16
|
613 << "updates: " << update_count << std::endl
|
Chris@16
|
614 << "gaps: " << gap_count << std::endl
|
Chris@16
|
615 << "gap nodes: " << gap_node_count << std::endl
|
Chris@16
|
616 << std::endl;
|
Chris@16
|
617 }
|
Chris@16
|
618
|
Chris@16
|
619 void print_flow_values(std::ostream& os) const {
|
Chris@16
|
620 os << "flow values" << std::endl;
|
Chris@16
|
621 vertex_iterator u_iter, u_end;
|
Chris@16
|
622 out_edge_iterator ei, e_end;
|
Chris@16
|
623 for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
|
Chris@16
|
624 for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
|
Chris@16
|
625 if (get(capacity, *ei) > 0)
|
Chris@16
|
626 os << *u_iter << " " << target(*ei, g) << " "
|
Chris@16
|
627 << (get(capacity, *ei) - get(residual_capacity, *ei)) << std::endl;
|
Chris@16
|
628 os << std::endl;
|
Chris@16
|
629 }
|
Chris@16
|
630
|
Chris@16
|
631 //=======================================================================
|
Chris@16
|
632
|
Chris@16
|
633 Graph& g;
|
Chris@16
|
634 vertices_size_type n;
|
Chris@16
|
635 vertices_size_type nm;
|
Chris@16
|
636 EdgeCapacityMap capacity;
|
Chris@16
|
637 vertex_descriptor src;
|
Chris@16
|
638 vertex_descriptor sink;
|
Chris@16
|
639 VertexIndexMap index;
|
Chris@16
|
640
|
Chris@16
|
641 // will need to use random_access_property_map with these
|
Chris@16
|
642 std::vector< FlowValue > excess_flow_data;
|
Chris@16
|
643 iterator_property_map<typename std::vector<FlowValue>::iterator, VertexIndexMap> excess_flow;
|
Chris@16
|
644 std::vector< std::pair<out_edge_iterator, out_edge_iterator> > current_data;
|
Chris@16
|
645 iterator_property_map<
|
Chris@16
|
646 typename std::vector< std::pair<out_edge_iterator, out_edge_iterator> >::iterator,
|
Chris@16
|
647 VertexIndexMap> current;
|
Chris@16
|
648 std::vector< distance_size_type > distance_data;
|
Chris@16
|
649 iterator_property_map<
|
Chris@16
|
650 typename std::vector< distance_size_type >::iterator,
|
Chris@16
|
651 VertexIndexMap> distance;
|
Chris@16
|
652 std::vector< default_color_type > color_data;
|
Chris@16
|
653 iterator_property_map<
|
Chris@16
|
654 std::vector< default_color_type >::iterator,
|
Chris@16
|
655 VertexIndexMap> color;
|
Chris@16
|
656
|
Chris@16
|
657 // Edge Property Maps that must be interior to the graph
|
Chris@16
|
658 ReverseEdgeMap reverse_edge;
|
Chris@16
|
659 ResidualCapacityEdgeMap residual_capacity;
|
Chris@16
|
660
|
Chris@16
|
661 LayerArray layers;
|
Chris@16
|
662 std::vector< list_iterator > layer_list_ptr_data;
|
Chris@16
|
663 iterator_property_map<typename std::vector< list_iterator >::iterator, VertexIndexMap> layer_list_ptr;
|
Chris@16
|
664 distance_size_type max_distance; // maximal distance
|
Chris@16
|
665 distance_size_type max_active; // maximal distance with active node
|
Chris@16
|
666 distance_size_type min_active; // minimal distance with active node
|
Chris@16
|
667 boost::queue<vertex_descriptor> Q;
|
Chris@16
|
668
|
Chris@16
|
669 // Statistics counters
|
Chris@16
|
670 long push_count;
|
Chris@16
|
671 long update_count;
|
Chris@16
|
672 long relabel_count;
|
Chris@16
|
673 long gap_count;
|
Chris@16
|
674 long gap_node_count;
|
Chris@16
|
675
|
Chris@16
|
676 inline double global_update_frequency() { return 0.5; }
|
Chris@16
|
677 inline vertices_size_type alpha() { return 6; }
|
Chris@16
|
678 inline long beta() { return 12; }
|
Chris@16
|
679
|
Chris@16
|
680 long work_since_last_update;
|
Chris@16
|
681 };
|
Chris@16
|
682
|
Chris@16
|
683 } // namespace detail
|
Chris@16
|
684
|
Chris@16
|
685 template <class Graph,
|
Chris@16
|
686 class CapacityEdgeMap, class ResidualCapacityEdgeMap,
|
Chris@16
|
687 class ReverseEdgeMap, class VertexIndexMap>
|
Chris@16
|
688 typename property_traits<CapacityEdgeMap>::value_type
|
Chris@16
|
689 push_relabel_max_flow
|
Chris@16
|
690 (Graph& g,
|
Chris@16
|
691 typename graph_traits<Graph>::vertex_descriptor src,
|
Chris@16
|
692 typename graph_traits<Graph>::vertex_descriptor sink,
|
Chris@16
|
693 CapacityEdgeMap cap, ResidualCapacityEdgeMap res,
|
Chris@16
|
694 ReverseEdgeMap rev, VertexIndexMap index_map)
|
Chris@16
|
695 {
|
Chris@16
|
696 typedef typename property_traits<CapacityEdgeMap>::value_type FlowValue;
|
Chris@16
|
697
|
Chris@16
|
698 detail::push_relabel<Graph, CapacityEdgeMap, ResidualCapacityEdgeMap,
|
Chris@16
|
699 ReverseEdgeMap, VertexIndexMap, FlowValue>
|
Chris@16
|
700 algo(g, cap, res, rev, src, sink, index_map);
|
Chris@16
|
701
|
Chris@16
|
702 FlowValue flow = algo.maximum_preflow();
|
Chris@16
|
703
|
Chris@16
|
704 algo.convert_preflow_to_flow();
|
Chris@16
|
705
|
Chris@16
|
706 BOOST_ASSERT(algo.is_flow());
|
Chris@16
|
707 BOOST_ASSERT(algo.is_optimal());
|
Chris@16
|
708
|
Chris@16
|
709 return flow;
|
Chris@16
|
710 } // push_relabel_max_flow()
|
Chris@16
|
711
|
Chris@16
|
712 template <class Graph, class P, class T, class R>
|
Chris@16
|
713 typename detail::edge_capacity_value<Graph, P, T, R>::type
|
Chris@16
|
714 push_relabel_max_flow
|
Chris@16
|
715 (Graph& g,
|
Chris@16
|
716 typename graph_traits<Graph>::vertex_descriptor src,
|
Chris@16
|
717 typename graph_traits<Graph>::vertex_descriptor sink,
|
Chris@16
|
718 const bgl_named_params<P, T, R>& params)
|
Chris@16
|
719 {
|
Chris@16
|
720 return push_relabel_max_flow
|
Chris@16
|
721 (g, src, sink,
|
Chris@16
|
722 choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
|
Chris@16
|
723 choose_pmap(get_param(params, edge_residual_capacity),
|
Chris@16
|
724 g, edge_residual_capacity),
|
Chris@16
|
725 choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
|
Chris@16
|
726 choose_const_pmap(get_param(params, vertex_index), g, vertex_index)
|
Chris@16
|
727 );
|
Chris@16
|
728 }
|
Chris@16
|
729
|
Chris@16
|
730 template <class Graph>
|
Chris@16
|
731 typename property_traits<
|
Chris@16
|
732 typename property_map<Graph, edge_capacity_t>::const_type
|
Chris@16
|
733 >::value_type
|
Chris@16
|
734 push_relabel_max_flow
|
Chris@16
|
735 (Graph& g,
|
Chris@16
|
736 typename graph_traits<Graph>::vertex_descriptor src,
|
Chris@16
|
737 typename graph_traits<Graph>::vertex_descriptor sink)
|
Chris@16
|
738 {
|
Chris@16
|
739 bgl_named_params<int, buffer_param_t> params(0); // bogus empty param
|
Chris@16
|
740 return push_relabel_max_flow(g, src, sink, params);
|
Chris@16
|
741 }
|
Chris@16
|
742
|
Chris@16
|
743 } // namespace boost
|
Chris@16
|
744
|
Chris@16
|
745 #endif // BOOST_PUSH_RELABEL_MAX_FLOW_HPP
|
Chris@16
|
746
|