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