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