annotate DEPENDENCIES/generic/include/boost/graph/push_relabel_max_flow.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents 2665513ce2d3
children
rev   line source
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