source: NonGTP/Boost/boost/graph/push_relabel_max_flow.hpp @ 857

Revision 857, 27.0 KB checked in by igarcia, 18 years ago (diff)
Line 
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
25namespace 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
Note: See TracBrowser for help on using the repository browser.