Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:43:06

0001 //=======================================================================
0002 // Copyright 2000 University of Notre Dame.
0003 // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee
0004 //
0005 // Distributed under the Boost Software License, Version 1.0. (See
0006 // accompanying file LICENSE_1_0.txt or copy at
0007 // http://www.boost.org/LICENSE_1_0.txt)
0008 //=======================================================================
0009 
0010 #ifndef BOOST_PUSH_RELABEL_MAX_FLOW_HPP
0011 #define BOOST_PUSH_RELABEL_MAX_FLOW_HPP
0012 
0013 #include <boost/config.hpp>
0014 #include <boost/assert.hpp>
0015 #include <vector>
0016 #include <list>
0017 #include <iosfwd>
0018 #include <algorithm> // for std::min and std::max
0019 
0020 #include <boost/pending/queue.hpp>
0021 #include <boost/limits.hpp>
0022 #include <boost/graph/graph_concepts.hpp>
0023 #include <boost/graph/named_function_params.hpp>
0024 
0025 namespace boost
0026 {
0027 
0028 namespace detail
0029 {
0030 
0031     // This implementation is based on Goldberg's
0032     // "On Implementing Push-Relabel Method for the Maximum Flow Problem"
0033     // by B.V. Cherkassky and A.V. Goldberg, IPCO '95, pp. 157--171
0034     // and on the h_prf.c and hi_pr.c code written by the above authors.
0035 
0036     // This implements the highest-label version of the push-relabel method
0037     // with the global relabeling and gap relabeling heuristics.
0038 
0039     // The terms "rank", "distance", "height" are synonyms in
0040     // Goldberg's implementation, paper and in the CLR.  A "layer" is a
0041     // group of vertices with the same distance. The vertices in each
0042     // layer are categorized as active or inactive.  An active vertex
0043     // has positive excess flow and its distance is less than n (it is
0044     // not blocked).
0045 
0046     template < class Vertex > struct preflow_layer
0047     {
0048         std::list< Vertex > active_vertices;
0049         std::list< Vertex > inactive_vertices;
0050     };
0051 
0052     template < class Graph,
0053         class EdgeCapacityMap, // integer value type
0054         class ResidualCapacityEdgeMap, class ReverseEdgeMap,
0055         class VertexIndexMap, // vertex_descriptor -> integer
0056         class FlowValue >
0057     class push_relabel
0058     {
0059     public:
0060         typedef graph_traits< Graph > Traits;
0061         typedef typename Traits::vertex_descriptor vertex_descriptor;
0062         typedef typename Traits::edge_descriptor edge_descriptor;
0063         typedef typename Traits::vertex_iterator vertex_iterator;
0064         typedef typename Traits::out_edge_iterator out_edge_iterator;
0065         typedef typename Traits::vertices_size_type vertices_size_type;
0066         typedef typename Traits::edges_size_type edges_size_type;
0067 
0068         typedef preflow_layer< vertex_descriptor > Layer;
0069         typedef std::vector< Layer > LayerArray;
0070         typedef typename LayerArray::iterator layer_iterator;
0071         typedef typename LayerArray::size_type distance_size_type;
0072 
0073         typedef color_traits< default_color_type > ColorTraits;
0074 
0075         //=======================================================================
0076         // Some helper predicates
0077 
0078         inline bool is_admissible(vertex_descriptor u, vertex_descriptor v)
0079         {
0080             return get(distance, u) == get(distance, v) + 1;
0081         }
0082         inline bool is_residual_edge(edge_descriptor a)
0083         {
0084             return 0 < get(residual_capacity, a);
0085         }
0086         inline bool is_saturated(edge_descriptor a)
0087         {
0088             return get(residual_capacity, a) == 0;
0089         }
0090 
0091         //=======================================================================
0092         // Layer List Management Functions
0093 
0094         typedef typename std::list< vertex_descriptor >::iterator list_iterator;
0095 
0096         void add_to_active_list(vertex_descriptor u, Layer& layer)
0097         {
0098             BOOST_USING_STD_MIN();
0099             BOOST_USING_STD_MAX();
0100             layer.active_vertices.push_front(u);
0101             max_active = max BOOST_PREVENT_MACRO_SUBSTITUTION(
0102                 get(distance, u), max_active);
0103             min_active = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0104                 get(distance, u), min_active);
0105             layer_list_ptr[u] = layer.active_vertices.begin();
0106         }
0107         void remove_from_active_list(vertex_descriptor u)
0108         {
0109             layers[get(distance, u)].active_vertices.erase(layer_list_ptr[u]);
0110         }
0111 
0112         void add_to_inactive_list(vertex_descriptor u, Layer& layer)
0113         {
0114             layer.inactive_vertices.push_front(u);
0115             layer_list_ptr[u] = layer.inactive_vertices.begin();
0116         }
0117         void remove_from_inactive_list(vertex_descriptor u)
0118         {
0119             layers[get(distance, u)].inactive_vertices.erase(layer_list_ptr[u]);
0120         }
0121 
0122         //=======================================================================
0123         // initialization
0124         push_relabel(Graph& g_, EdgeCapacityMap cap,
0125             ResidualCapacityEdgeMap res, ReverseEdgeMap rev,
0126             vertex_descriptor src_, vertex_descriptor sink_, VertexIndexMap idx)
0127         : g(g_)
0128         , n(num_vertices(g_))
0129         , capacity(cap)
0130         , src(src_)
0131         , sink(sink_)
0132         , index(idx)
0133         , excess_flow_data(num_vertices(g_))
0134         , excess_flow(excess_flow_data.begin(), idx)
0135         , current_data(num_vertices(g_), out_edges(*vertices(g_).first, g_))
0136         , current(current_data.begin(), idx)
0137         , distance_data(num_vertices(g_))
0138         , distance(distance_data.begin(), idx)
0139         , color_data(num_vertices(g_))
0140         , color(color_data.begin(), idx)
0141         , reverse_edge(rev)
0142         , residual_capacity(res)
0143         , layers(num_vertices(g_))
0144         , layer_list_ptr_data(
0145               num_vertices(g_), layers.front().inactive_vertices.end())
0146         , layer_list_ptr(layer_list_ptr_data.begin(), idx)
0147         , push_count(0)
0148         , update_count(0)
0149         , relabel_count(0)
0150         , gap_count(0)
0151         , gap_node_count(0)
0152         , work_since_last_update(0)
0153         {
0154             vertex_iterator u_iter, u_end;
0155             // Don't count the reverse edges
0156             edges_size_type m = num_edges(g) / 2;
0157             nm = alpha() * n + m;
0158 
0159             // Initialize flow to zero which means initializing
0160             // the residual capacity to equal the capacity.
0161             out_edge_iterator ei, e_end;
0162             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0163                  ++u_iter)
0164                 for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end;
0165                      ++ei)
0166                 {
0167                     put(residual_capacity, *ei, get(capacity, *ei));
0168                 }
0169 
0170             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0171                  ++u_iter)
0172             {
0173                 vertex_descriptor u = *u_iter;
0174                 put(excess_flow, u, 0);
0175                 current[u] = out_edges(u, g);
0176             }
0177 
0178             bool overflow_detected = false;
0179             FlowValue test_excess = 0;
0180 
0181             out_edge_iterator a_iter, a_end;
0182             for (boost::tie(a_iter, a_end) = out_edges(src, g); a_iter != a_end;
0183                  ++a_iter)
0184                 if (target(*a_iter, g) != src)
0185                     test_excess += get(residual_capacity, *a_iter);
0186             if (test_excess > (std::numeric_limits< FlowValue >::max)())
0187                 overflow_detected = true;
0188 
0189             if (overflow_detected)
0190                 put(excess_flow, src,
0191                     (std::numeric_limits< FlowValue >::max)());
0192             else
0193             {
0194                 put(excess_flow, src, 0);
0195                 for (boost::tie(a_iter, a_end) = out_edges(src, g);
0196                      a_iter != a_end; ++a_iter)
0197                 {
0198                     edge_descriptor a = *a_iter;
0199                     vertex_descriptor tgt = target(a, g);
0200                     if (tgt != src)
0201                     {
0202                         ++push_count;
0203                         FlowValue delta = get(residual_capacity, a);
0204                         put(residual_capacity, a,
0205                             get(residual_capacity, a) - delta);
0206                         edge_descriptor rev = get(reverse_edge, a);
0207                         put(residual_capacity, rev,
0208                             get(residual_capacity, rev) + delta);
0209                         put(excess_flow, tgt, get(excess_flow, tgt) + delta);
0210                     }
0211                 }
0212             }
0213             max_distance = num_vertices(g) - 1;
0214             max_active = 0;
0215             min_active = n;
0216 
0217             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0218                  ++u_iter)
0219             {
0220                 vertex_descriptor u = *u_iter;
0221                 if (u == sink)
0222                 {
0223                     put(distance, u, 0);
0224                     continue;
0225                 }
0226                 else if (u == src && !overflow_detected)
0227                     put(distance, u, n);
0228                 else
0229                     put(distance, u, 1);
0230 
0231                 if (get(excess_flow, u) > 0)
0232                     add_to_active_list(u, layers[1]);
0233                 else if (get(distance, u) < n)
0234                     add_to_inactive_list(u, layers[1]);
0235             }
0236 
0237         } // push_relabel constructor
0238 
0239         //=======================================================================
0240         // This is a breadth-first search over the residual graph
0241         // (well, actually the reverse of the residual graph).
0242         // Would be cool to have a graph view adaptor for hiding certain
0243         // edges, like the saturated (non-residual) edges in this case.
0244         // Goldberg's implementation abused "distance" for the coloring.
0245         void global_distance_update()
0246         {
0247             BOOST_USING_STD_MAX();
0248             ++update_count;
0249             vertex_iterator u_iter, u_end;
0250             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0251                  ++u_iter)
0252             {
0253                 put(color, *u_iter, ColorTraits::white());
0254                 put(distance, *u_iter, n);
0255             }
0256             put(color, sink, ColorTraits::gray());
0257             put(distance, sink, 0);
0258 
0259             for (distance_size_type l = 0; l <= max_distance; ++l)
0260             {
0261                 layers[l].active_vertices.clear();
0262                 layers[l].inactive_vertices.clear();
0263             }
0264 
0265             max_distance = max_active = 0;
0266             min_active = n;
0267 
0268             Q.push(sink);
0269             while (!Q.empty())
0270             {
0271                 vertex_descriptor u = Q.top();
0272                 Q.pop();
0273                 distance_size_type d_v = get(distance, u) + 1;
0274 
0275                 out_edge_iterator ai, a_end;
0276                 for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai)
0277                 {
0278                     edge_descriptor a = *ai;
0279                     vertex_descriptor v = target(a, g);
0280                     if (get(color, v) == ColorTraits::white()
0281                         && is_residual_edge(get(reverse_edge, a)))
0282                     {
0283                         put(distance, v, d_v);
0284                         put(color, v, ColorTraits::gray());
0285                         current[v] = out_edges(v, g);
0286                         max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(
0287                             d_v, max_distance);
0288 
0289                         if (get(excess_flow, v) > 0)
0290                             add_to_active_list(v, layers[d_v]);
0291                         else
0292                             add_to_inactive_list(v, layers[d_v]);
0293 
0294                         Q.push(v);
0295                     }
0296                 }
0297             }
0298         } // global_distance_update()
0299 
0300         //=======================================================================
0301         // This function is called "push" in Goldberg's h_prf implementation,
0302         // but it is called "discharge" in the paper and in hi_pr.c.
0303         void discharge(vertex_descriptor u)
0304         {
0305             BOOST_ASSERT(get(excess_flow, u) > 0);
0306             while (1)
0307             {
0308                 out_edge_iterator ai, ai_end;
0309                 for (boost::tie(ai, ai_end) = current[u]; ai != ai_end; ++ai)
0310                 {
0311                     edge_descriptor a = *ai;
0312                     if (is_residual_edge(a))
0313                     {
0314                         vertex_descriptor v = target(a, g);
0315                         if (is_admissible(u, v))
0316                         {
0317                             ++push_count;
0318                             if (v != sink && get(excess_flow, v) == 0)
0319                             {
0320                                 remove_from_inactive_list(v);
0321                                 add_to_active_list(v, layers[get(distance, v)]);
0322                             }
0323                             push_flow(a);
0324                             if (get(excess_flow, u) == 0)
0325                                 break;
0326                         }
0327                     }
0328                 } // for out_edges of i starting from current
0329 
0330                 Layer& layer = layers[get(distance, u)];
0331                 distance_size_type du = get(distance, u);
0332 
0333                 if (ai == ai_end)
0334                 { // i must be relabeled
0335                     relabel_distance(u);
0336                     if (layer.active_vertices.empty()
0337                         && layer.inactive_vertices.empty())
0338                         gap(du);
0339                     if (get(distance, u) == n)
0340                         break;
0341                 }
0342                 else
0343                 { // i is no longer active
0344                     current[u].first = ai;
0345                     add_to_inactive_list(u, layer);
0346                     break;
0347                 }
0348             } // while (1)
0349         } // discharge()
0350 
0351         //=======================================================================
0352         // This corresponds to the "push" update operation of the paper,
0353         // not the "push" function in Goldberg's h_prf.c implementation.
0354         // The idea is to push the excess flow from from vertex u to v.
0355         void push_flow(edge_descriptor u_v)
0356         {
0357             vertex_descriptor u = source(u_v, g), v = target(u_v, g);
0358 
0359             BOOST_USING_STD_MIN();
0360             FlowValue flow_delta = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0361                 get(excess_flow, u), get(residual_capacity, u_v));
0362 
0363             put(residual_capacity, u_v,
0364                 get(residual_capacity, u_v) - flow_delta);
0365             edge_descriptor rev = get(reverse_edge, u_v);
0366             put(residual_capacity, rev,
0367                 get(residual_capacity, rev) + flow_delta);
0368 
0369             put(excess_flow, u, get(excess_flow, u) - flow_delta);
0370             put(excess_flow, v, get(excess_flow, v) + flow_delta);
0371         } // push_flow()
0372 
0373         //=======================================================================
0374         // The main purpose of this routine is to set distance[v]
0375         // to the smallest value allowed by the valid labeling constraints,
0376         // which are:
0377         // distance[t] = 0
0378         // distance[u] <= distance[v] + 1   for every residual edge (u,v)
0379         //
0380         distance_size_type relabel_distance(vertex_descriptor u)
0381         {
0382             BOOST_USING_STD_MAX();
0383             ++relabel_count;
0384             work_since_last_update += beta();
0385 
0386             distance_size_type min_distance = num_vertices(g);
0387             put(distance, u, min_distance);
0388 
0389             // Examine the residual out-edges of vertex i, choosing the
0390             // edge whose target vertex has the minimal distance.
0391             out_edge_iterator ai, a_end, min_edge_iter;
0392             for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai)
0393             {
0394                 ++work_since_last_update;
0395                 edge_descriptor a = *ai;
0396                 vertex_descriptor v = target(a, g);
0397                 if (is_residual_edge(a) && get(distance, v) < min_distance)
0398                 {
0399                     min_distance = get(distance, v);
0400                     min_edge_iter = ai;
0401                 }
0402             }
0403             ++min_distance;
0404             if (min_distance < n)
0405             {
0406                 put(distance, u, min_distance); // this is the main action
0407                 current[u].first = min_edge_iter;
0408                 max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION(
0409                     min_distance, max_distance);
0410             }
0411             return min_distance;
0412         } // relabel_distance()
0413 
0414         //=======================================================================
0415         // cleanup beyond the gap
0416         void gap(distance_size_type empty_distance)
0417         {
0418             ++gap_count;
0419 
0420             distance_size_type r; // distance of layer before the current layer
0421             r = empty_distance - 1;
0422 
0423             // Set the distance for the vertices beyond the gap to "infinity".
0424             for (layer_iterator l = layers.begin() + empty_distance + 1;
0425                  l < layers.begin() + max_distance; ++l)
0426             {
0427                 list_iterator i;
0428                 for (i = l->inactive_vertices.begin();
0429                      i != l->inactive_vertices.end(); ++i)
0430                 {
0431                     put(distance, *i, n);
0432                     ++gap_node_count;
0433                 }
0434                 l->inactive_vertices.clear();
0435             }
0436             max_distance = r;
0437             max_active = r;
0438         }
0439 
0440         //=======================================================================
0441         // This is the core part of the algorithm, "phase one".
0442         FlowValue maximum_preflow()
0443         {
0444             work_since_last_update = 0;
0445 
0446             while (max_active >= min_active)
0447             { // "main" loop
0448 
0449                 Layer& layer = layers[max_active];
0450                 list_iterator u_iter = layer.active_vertices.begin();
0451 
0452                 if (u_iter == layer.active_vertices.end())
0453                     --max_active;
0454                 else
0455                 {
0456                     vertex_descriptor u = *u_iter;
0457                     remove_from_active_list(u);
0458 
0459                     discharge(u);
0460 
0461                     if (work_since_last_update * global_update_frequency() > nm)
0462                     {
0463                         global_distance_update();
0464                         work_since_last_update = 0;
0465                     }
0466                 }
0467             } // while (max_active >= min_active)
0468 
0469             return get(excess_flow, sink);
0470         } // maximum_preflow()
0471 
0472         //=======================================================================
0473         // remove excess flow, the "second phase"
0474         // This does a DFS on the reverse flow graph of nodes with excess flow.
0475         // If a cycle is found, cancel it.
0476         // Return the nodes with excess flow in topological order.
0477         //
0478         // Unlike the prefl_to_flow() implementation, we use
0479         //   "color" instead of "distance" for the DFS labels
0480         //   "parent" instead of nl_prev for the DFS tree
0481         //   "topo_next" instead of nl_next for the topological ordering
0482         void convert_preflow_to_flow()
0483         {
0484             vertex_iterator u_iter, u_end;
0485             out_edge_iterator ai, a_end;
0486 
0487             vertex_descriptor r, restart, u;
0488 
0489             std::vector< vertex_descriptor > parent(n);
0490             std::vector< vertex_descriptor > topo_next(n);
0491 
0492             vertex_descriptor tos(parent[0]),
0493                 bos(parent[0]); // bogus initialization, just to avoid warning
0494             bool bos_null = true;
0495 
0496             // handle self-loops
0497             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0498                  ++u_iter)
0499                 for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end;
0500                      ++ai)
0501                     if (target(*ai, g) == *u_iter)
0502                         put(residual_capacity, *ai, get(capacity, *ai));
0503 
0504             // initialize
0505             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0506                  ++u_iter)
0507             {
0508                 u = *u_iter;
0509                 put(color, u, ColorTraits::white());
0510                 parent[get(index, u)] = u;
0511                 current[u] = out_edges(u, g);
0512             }
0513             // eliminate flow cycles and topologically order the vertices
0514             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0515                  ++u_iter)
0516             {
0517                 u = *u_iter;
0518                 if (get(color, u) == ColorTraits::white()
0519                     && get(excess_flow, u) > 0 && u != src && u != sink)
0520                 {
0521                     r = u;
0522                     put(color, r, ColorTraits::gray());
0523                     while (1)
0524                     {
0525                         for (; current[u].first != current[u].second;
0526                              ++current[u].first)
0527                         {
0528                             edge_descriptor a = *current[u].first;
0529                             if (get(capacity, a) == 0 && is_residual_edge(a))
0530                             {
0531                                 vertex_descriptor v = target(a, g);
0532                                 if (get(color, v) == ColorTraits::white())
0533                                 {
0534                                     put(color, v, ColorTraits::gray());
0535                                     parent[get(index, v)] = u;
0536                                     u = v;
0537                                     break;
0538                                 }
0539                                 else if (get(color, v) == ColorTraits::gray())
0540                                 {
0541                                     // find minimum flow on the cycle
0542                                     FlowValue delta = get(residual_capacity, a);
0543                                     while (1)
0544                                     {
0545                                         BOOST_USING_STD_MIN();
0546                                         delta = min
0547                                             BOOST_PREVENT_MACRO_SUBSTITUTION(
0548                                                 delta,
0549                                                 get(residual_capacity,
0550                                                     *current[v].first));
0551                                         if (v == u)
0552                                             break;
0553                                         else
0554                                             v = target(*current[v].first, g);
0555                                     }
0556                                     // remove delta flow units
0557                                     v = u;
0558                                     while (1)
0559                                     {
0560                                         a = *current[v].first;
0561                                         put(residual_capacity, a,
0562                                             get(residual_capacity, a) - delta);
0563                                         edge_descriptor rev
0564                                             = get(reverse_edge, a);
0565                                         put(residual_capacity, rev,
0566                                             get(residual_capacity, rev)
0567                                                 + delta);
0568                                         v = target(a, g);
0569                                         if (v == u)
0570                                             break;
0571                                     }
0572 
0573                                     // back-out of DFS to the first saturated
0574                                     // edge
0575                                     restart = u;
0576                                     for (v = target(*current[u].first, g);
0577                                          v != u; v = target(a, g))
0578                                     {
0579                                         a = *current[v].first;
0580                                         if (get(color, v)
0581                                                 == ColorTraits::white()
0582                                             || is_saturated(a))
0583                                         {
0584                                             put(color,
0585                                                 target(*current[v].first, g),
0586                                                 ColorTraits::white());
0587                                             if (get(color, v)
0588                                                 != ColorTraits::white())
0589                                                 restart = v;
0590                                         }
0591                                     }
0592                                     if (restart != u)
0593                                     {
0594                                         u = restart;
0595                                         ++current[u].first;
0596                                         break;
0597                                     }
0598                                 } // else if (color[v] == ColorTraits::gray())
0599                             } // if (get(capacity, a) == 0 ...
0600                         } // for out_edges(u, g)  (though "u" changes during
0601                           // loop)
0602 
0603                         if (current[u].first == current[u].second)
0604                         {
0605                             // scan of i is complete
0606                             put(color, u, ColorTraits::black());
0607                             if (u != src)
0608                             {
0609                                 if (bos_null)
0610                                 {
0611                                     bos = u;
0612                                     bos_null = false;
0613                                     tos = u;
0614                                 }
0615                                 else
0616                                 {
0617                                     topo_next[get(index, u)] = tos;
0618                                     tos = u;
0619                                 }
0620                             }
0621                             if (u != r)
0622                             {
0623                                 u = parent[get(index, u)];
0624                                 ++current[u].first;
0625                             }
0626                             else
0627                                 break;
0628                         }
0629                     } // while (1)
0630                 } // if (color[u] == white && excess_flow[u] > 0 & ...)
0631             } // for all vertices in g
0632 
0633             // return excess flows
0634             // note that the sink is not on the stack
0635             if (!bos_null)
0636             {
0637                 for (u = tos; u != bos; u = topo_next[get(index, u)])
0638                 {
0639                     boost::tie(ai, a_end) = out_edges(u, g);
0640                     while (get(excess_flow, u) > 0 && ai != a_end)
0641                     {
0642                         if (get(capacity, *ai) == 0 && is_residual_edge(*ai))
0643                             push_flow(*ai);
0644                         ++ai;
0645                     }
0646                 }
0647                 // do the bottom
0648                 u = bos;
0649                 boost::tie(ai, a_end) = out_edges(u, g);
0650                 while (get(excess_flow, u) > 0 && ai != a_end)
0651                 {
0652                     if (get(capacity, *ai) == 0 && is_residual_edge(*ai))
0653                         push_flow(*ai);
0654                     ++ai;
0655                 }
0656             }
0657 
0658         } // convert_preflow_to_flow()
0659 
0660         //=======================================================================
0661         inline bool is_flow()
0662         {
0663             vertex_iterator u_iter, u_end;
0664             out_edge_iterator ai, a_end;
0665 
0666             // check edge flow values
0667             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0668                  ++u_iter)
0669             {
0670                 for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end;
0671                      ++ai)
0672                 {
0673                     edge_descriptor a = *ai;
0674                     if (get(capacity, a) > 0)
0675                         if ((get(residual_capacity, a)
0676                                     + get(
0677                                         residual_capacity, get(reverse_edge, a))
0678                                 != get(capacity, a)
0679                                     + get(capacity, get(reverse_edge, a)))
0680                             || (get(residual_capacity, a) < 0)
0681                             || (get(residual_capacity, get(reverse_edge, a))
0682                                 < 0))
0683                             return false;
0684                 }
0685             }
0686 
0687             // check conservation
0688             FlowValue sum;
0689             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0690                  ++u_iter)
0691             {
0692                 vertex_descriptor u = *u_iter;
0693                 if (u != src && u != sink)
0694                 {
0695                     if (get(excess_flow, u) != 0)
0696                         return false;
0697                     sum = 0;
0698                     for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end;
0699                          ++ai)
0700                         if (get(capacity, *ai) > 0)
0701                             sum -= get(capacity, *ai)
0702                                 - get(residual_capacity, *ai);
0703                         else
0704                             sum += get(residual_capacity, *ai);
0705 
0706                     if (get(excess_flow, u) != sum)
0707                         return false;
0708                 }
0709             }
0710 
0711             return true;
0712         } // is_flow()
0713 
0714         bool is_optimal()
0715         {
0716             // check if mincut is saturated...
0717             global_distance_update();
0718             return get(distance, src) >= n;
0719         }
0720 
0721         void print_statistics(std::ostream& os) const
0722         {
0723             os << "pushes:     " << push_count << std::endl
0724                << "relabels:   " << relabel_count << std::endl
0725                << "updates:    " << update_count << std::endl
0726                << "gaps:       " << gap_count << std::endl
0727                << "gap nodes:  " << gap_node_count << std::endl
0728                << std::endl;
0729         }
0730 
0731         void print_flow_values(std::ostream& os) const
0732         {
0733             os << "flow values" << std::endl;
0734             vertex_iterator u_iter, u_end;
0735             out_edge_iterator ei, e_end;
0736             for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end;
0737                  ++u_iter)
0738                 for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end;
0739                      ++ei)
0740                     if (get(capacity, *ei) > 0)
0741                         os << *u_iter << " " << target(*ei, g) << " "
0742                            << (get(capacity, *ei) - get(residual_capacity, *ei))
0743                            << std::endl;
0744             os << std::endl;
0745         }
0746 
0747         //=======================================================================
0748 
0749         Graph& g;
0750         vertices_size_type n;
0751         vertices_size_type nm;
0752         EdgeCapacityMap capacity;
0753         vertex_descriptor src;
0754         vertex_descriptor sink;
0755         VertexIndexMap index;
0756 
0757         // will need to use random_access_property_map with these
0758         std::vector< FlowValue > excess_flow_data;
0759         iterator_property_map< typename std::vector< FlowValue >::iterator,
0760             VertexIndexMap >
0761             excess_flow;
0762         std::vector< std::pair< out_edge_iterator, out_edge_iterator > >
0763             current_data;
0764         iterator_property_map<
0765             typename std::vector<
0766                 std::pair< out_edge_iterator, out_edge_iterator > >::iterator,
0767             VertexIndexMap >
0768             current;
0769         std::vector< distance_size_type > distance_data;
0770         iterator_property_map<
0771             typename std::vector< distance_size_type >::iterator,
0772             VertexIndexMap >
0773             distance;
0774         std::vector< default_color_type > color_data;
0775         iterator_property_map< std::vector< default_color_type >::iterator,
0776             VertexIndexMap >
0777             color;
0778 
0779         // Edge Property Maps that must be interior to the graph
0780         ReverseEdgeMap reverse_edge;
0781         ResidualCapacityEdgeMap residual_capacity;
0782 
0783         LayerArray layers;
0784         std::vector< list_iterator > layer_list_ptr_data;
0785         iterator_property_map< typename std::vector< list_iterator >::iterator,
0786             VertexIndexMap >
0787             layer_list_ptr;
0788         distance_size_type max_distance; // maximal distance
0789         distance_size_type max_active; // maximal distance with active node
0790         distance_size_type min_active; // minimal distance with active node
0791         boost::queue< vertex_descriptor > Q;
0792 
0793         // Statistics counters
0794         long push_count;
0795         long update_count;
0796         long relabel_count;
0797         long gap_count;
0798         long gap_node_count;
0799 
0800         inline double global_update_frequency() { return 0.5; }
0801         inline vertices_size_type alpha() { return 6; }
0802         inline long beta() { return 12; }
0803 
0804         long work_since_last_update;
0805     };
0806 
0807 } // namespace detail
0808 
0809 template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap,
0810     class ReverseEdgeMap, class VertexIndexMap >
0811 typename property_traits< CapacityEdgeMap >::value_type push_relabel_max_flow(
0812     Graph& g, typename graph_traits< Graph >::vertex_descriptor src,
0813     typename graph_traits< Graph >::vertex_descriptor sink, CapacityEdgeMap cap,
0814     ResidualCapacityEdgeMap res, ReverseEdgeMap rev, VertexIndexMap index_map)
0815 {
0816     typedef typename property_traits< CapacityEdgeMap >::value_type FlowValue;
0817 
0818     detail::push_relabel< Graph, CapacityEdgeMap, ResidualCapacityEdgeMap,
0819         ReverseEdgeMap, VertexIndexMap, FlowValue >
0820         algo(g, cap, res, rev, src, sink, index_map);
0821 
0822     FlowValue flow = algo.maximum_preflow();
0823 
0824     algo.convert_preflow_to_flow();
0825 
0826     BOOST_ASSERT(algo.is_flow());
0827     BOOST_ASSERT(algo.is_optimal());
0828 
0829     return flow;
0830 } // push_relabel_max_flow()
0831 
0832 template < class Graph, class P, class T, class R >
0833 typename detail::edge_capacity_value< Graph, P, T, R >::type
0834 push_relabel_max_flow(Graph& g,
0835     typename graph_traits< Graph >::vertex_descriptor src,
0836     typename graph_traits< Graph >::vertex_descriptor sink,
0837     const bgl_named_params< P, T, R >& params)
0838 {
0839     return push_relabel_max_flow(g, src, sink,
0840         choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
0841         choose_pmap(get_param(params, edge_residual_capacity), g,
0842             edge_residual_capacity),
0843         choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
0844         choose_const_pmap(get_param(params, vertex_index), g, vertex_index));
0845 }
0846 
0847 template < class Graph >
0848 typename property_traits<
0849     typename property_map< Graph, edge_capacity_t >::const_type >::value_type
0850 push_relabel_max_flow(Graph& g,
0851     typename graph_traits< Graph >::vertex_descriptor src,
0852     typename graph_traits< Graph >::vertex_descriptor sink)
0853 {
0854     bgl_named_params< int, buffer_param_t > params(0); // bogus empty param
0855     return push_relabel_max_flow(g, src, sink, params);
0856 }
0857 
0858 } // namespace boost
0859 
0860 #endif // BOOST_PUSH_RELABEL_MAX_FLOW_HPP