File indexing completed on 2024-05-12 05:46:56

0001 //  Copyright (c) 2006, Stephan Diederich
0002 //
0003 //  This code may be used under either of the following two licences:
0004 //
0005 //    Permission is hereby granted, free of charge, to any person
0006 //    obtaining a copy of this software and associated documentation
0007 //    files (the "Software"), to deal in the Software without
0008 //    restriction, including without limitation the rights to use,
0009 //    copy, modify, merge, publish, distribute, sublicense, and/or
0010 //    sell copies of the Software, and to permit persons to whom the
0011 //    Software is furnished to do so, subject to the following
0012 //    conditions:
0013 //
0014 //    The above copyright notice and this permission notice shall be
0015 //    included in all copies or substantial portions of the Software.
0016 //
0017 //    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0018 //    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
0019 //    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0020 //    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
0021 //    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
0022 //    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0023 //    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0024 //    OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
0025 //
0026 //  Or:
0027 //
0028 //    Distributed under the Boost Software License, Version 1.0.
0029 //    (See accompanying file LICENSE_1_0.txt or copy at
0030 //    https://www.boost.org/LICENSE_1_0.txt)
0031 
0032 #ifndef BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
0033 #define BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
0034 
0035 #include <boost/config.hpp>
0036 #include <boost/assert.hpp>
0037 #include <vector>
0038 #include <list>
0039 #include <utility>
0040 #include <iosfwd>
0041 #include <algorithm> // for std::min and std::max
0042 
0043 #include <boost/pending/queue.hpp>
0044 #include <boost/limits.hpp>
0045 #include <boost/property_map/property_map.hpp>
0046 #include <boost/none_t.hpp>
0047 #include <boost/graph/graph_concepts.hpp>
0048 #include <boost/graph/named_function_params.hpp>
0049 #include <boost/graph/lookup_edge.hpp>
0050 #include <boost/concept/assert.hpp>
0051 
0052 // The algorithm impelemented here is described in:
0053 //
0054 // Boykov, Y., Kolmogorov, V. "An Experimental Comparison of Min-Cut/Max-Flow
0055 // Algorithms for Energy Minimization in Vision", In IEEE Transactions on
0056 // Pattern Analysis and Machine Intelligence, vol. 26, no. 9, pp. 1124-1137,
0057 // Sep 2004.
0058 //
0059 // For further reading, also see:
0060 //
0061 // Kolmogorov, V. "Graph Based Algorithms for Scene Reconstruction from Two or
0062 // More Views". PhD thesis, Cornell University, Sep 2003.
0063 
0064 namespace boost {
0065 
0066 namespace detail {
0067 
0068 template <class Graph,
0069           class EdgeCapacityMap,
0070           class ResidualCapacityEdgeMap,
0071           class ReverseEdgeMap,
0072           class PredecessorMap,
0073           class ColorMap,
0074           class DistanceMap,
0075           class IndexMap>
0076 class bk_max_flow {
0077   typedef typename property_traits<EdgeCapacityMap>::value_type tEdgeVal;
0078   typedef graph_traits<Graph> tGraphTraits;
0079   typedef typename tGraphTraits::vertex_iterator vertex_iterator;
0080   typedef typename tGraphTraits::vertex_descriptor vertex_descriptor;
0081   typedef typename tGraphTraits::edge_descriptor edge_descriptor;
0082   typedef typename tGraphTraits::edge_iterator edge_iterator;
0083   typedef typename tGraphTraits::out_edge_iterator out_edge_iterator;
0084   typedef boost::queue<vertex_descriptor> tQueue;                               //queue of vertices, used in adoption-stage
0085   typedef typename property_traits<ColorMap>::value_type tColorValue;
0086   typedef color_traits<tColorValue> tColorTraits;
0087   typedef typename property_traits<DistanceMap>::value_type tDistanceVal;
0088 
0089     public:
0090       bk_max_flow(Graph& g,
0091                   EdgeCapacityMap cap,
0092                   ResidualCapacityEdgeMap res,
0093                   ReverseEdgeMap rev,
0094                   PredecessorMap pre,
0095                   ColorMap color,
0096                   DistanceMap dist,
0097                   IndexMap idx,
0098                   vertex_descriptor src,
0099                   vertex_descriptor sink):
0100       m_g(g),
0101       m_index_map(idx),
0102       m_cap_map(cap),
0103       m_res_cap_map(res),
0104       m_rev_edge_map(rev),
0105       m_pre_map(pre),
0106       m_tree_map(color),
0107       m_dist_map(dist),
0108       m_source(src),
0109       m_sink(sink),
0110       m_active_nodes(),
0111       m_in_active_list_vec(num_vertices(g), false),
0112       m_in_active_list_map(make_iterator_property_map(m_in_active_list_vec.begin(), m_index_map)),
0113       m_has_parent_vec(num_vertices(g), false),
0114       m_has_parent_map(make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)),
0115       m_time_vec(num_vertices(g), 0),
0116       m_time_map(make_iterator_property_map(m_time_vec.begin(), m_index_map)),
0117       m_flow(0),
0118       m_time(1),
0119       m_last_grow_vertex(graph_traits<Graph>::null_vertex()){
0120         // initialize the color-map with gray-values
0121         vertex_iterator vi, v_end;
0122         for(boost::tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi){
0123           set_tree(*vi, tColorTraits::gray());
0124         }
0125         // Initialize flow to zero which means initializing
0126         // the residual capacity equal to the capacity
0127         edge_iterator ei, e_end;
0128         for(boost::tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) {
0129           put(m_res_cap_map, *ei, get(m_cap_map, *ei));
0130           BOOST_ASSERT(get(m_rev_edge_map, get(m_rev_edge_map, *ei)) == *ei); //check if the reverse edge map is build up properly
0131         }
0132         //init the search trees with the two terminals
0133         set_tree(m_source, tColorTraits::black());
0134         set_tree(m_sink, tColorTraits::white());
0135         put(m_time_map, m_source, 1);
0136         put(m_time_map, m_sink, 1);
0137       }
0138 
0139       tEdgeVal max_flow(){
0140         //augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK
0141         augment_direct_paths();
0142         //start the main-loop
0143         while(true){
0144           bool path_found;
0145           edge_descriptor connecting_edge;
0146           boost::tie(connecting_edge, path_found) = grow(); //find a path from source to sink
0147           if(!path_found){
0148             //we're finished, no more paths were found
0149             break;
0150           }
0151           ++m_time;
0152           augment(connecting_edge); //augment that path
0153           adopt(); //rebuild search tree structure
0154         }
0155         return m_flow;
0156       }
0157 
0158       // the complete class is protected, as we want access to members in
0159       // derived test-class (see test/boykov_kolmogorov_max_flow_test.cpp)
0160     protected:
0161       void augment_direct_paths(){
0162         // in a first step, we augment all direct paths from source->NODE->sink
0163         // and additionally paths from source->sink. This improves especially
0164         // graphcuts for segmentation, as most of the nodes have source/sink
0165         // connects but shouldn't have an impact on other maxflow problems
0166         // (this is done in grow() anyway)
0167         out_edge_iterator ei, e_end;
0168         for(boost::tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei){
0169           edge_descriptor from_source = *ei;
0170           vertex_descriptor current_node = target(from_source, m_g);
0171           if(current_node == m_sink){
0172             tEdgeVal cap = get(m_res_cap_map, from_source);
0173             put(m_res_cap_map, from_source, 0);
0174             m_flow += cap;
0175             continue;
0176           }
0177           edge_descriptor to_sink;
0178           bool is_there;
0179           boost::tie(to_sink, is_there) = lookup_edge(current_node, m_sink, m_g);
0180           if(is_there){
0181             tEdgeVal cap_from_source = get(m_res_cap_map, from_source);
0182             tEdgeVal cap_to_sink = get(m_res_cap_map, to_sink);
0183             if(cap_from_source > cap_to_sink){
0184               set_tree(current_node, tColorTraits::black());
0185               add_active_node(current_node);
0186               set_edge_to_parent(current_node, from_source);
0187               put(m_dist_map, current_node, 1);
0188               put(m_time_map, current_node, 1);
0189               // add stuff to flow and update residuals. we don't need to
0190               // update reverse_edges, as incoming/outgoing edges to/from
0191               // source/sink don't count for max-flow
0192               put(m_res_cap_map, from_source, get(m_res_cap_map, from_source) - cap_to_sink);
0193               put(m_res_cap_map, to_sink, 0);
0194               m_flow += cap_to_sink;
0195             } else if(cap_to_sink > 0){
0196               set_tree(current_node, tColorTraits::white());
0197               add_active_node(current_node);
0198               set_edge_to_parent(current_node, to_sink);
0199               put(m_dist_map, current_node, 1);
0200               put(m_time_map, current_node, 1);
0201               // add stuff to flow and update residuals. we don't need to update
0202               // reverse_edges, as incoming/outgoing edges to/from source/sink
0203               // don't count for max-flow
0204               put(m_res_cap_map, to_sink, get(m_res_cap_map, to_sink) - cap_from_source);
0205               put(m_res_cap_map, from_source, 0);
0206               m_flow += cap_from_source;
0207             }
0208           } else if(get(m_res_cap_map, from_source)){
0209             // there is no sink connect, so we can't augment this path, but to
0210             // avoid adding m_source to the active nodes, we just activate this
0211             // node and set the appropriate things
0212             set_tree(current_node, tColorTraits::black());
0213             set_edge_to_parent(current_node, from_source);
0214             put(m_dist_map, current_node, 1);
0215             put(m_time_map, current_node, 1);
0216             add_active_node(current_node);
0217           }
0218         }
0219         for(boost::tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei){
0220           edge_descriptor to_sink = get(m_rev_edge_map, *ei);
0221           vertex_descriptor current_node = source(to_sink, m_g);
0222           if(get(m_res_cap_map, to_sink)){
0223             set_tree(current_node, tColorTraits::white());
0224             set_edge_to_parent(current_node, to_sink);
0225             put(m_dist_map, current_node, 1);
0226             put(m_time_map, current_node, 1);
0227             add_active_node(current_node);
0228           }
0229         }
0230       }
0231 
0232       /**
0233        * Returns a pair of an edge and a boolean. if the bool is true, the
0234        * edge is a connection of a found path from s->t , read "the link" and
0235        * source(returnVal, m_g) is the end of the path found in the source-tree
0236        * target(returnVal, m_g) is the beginning of the path found in the sink-tree
0237        */
0238       std::pair<edge_descriptor, bool> grow(){
0239         BOOST_ASSERT(m_orphans.empty());
0240         vertex_descriptor current_node;
0241         while((current_node = get_next_active_node()) != graph_traits<Graph>::null_vertex()){ //if there is one
0242           BOOST_ASSERT(get_tree(current_node) != tColorTraits::gray() &&
0243                        (has_parent(current_node) ||
0244                          current_node == m_source ||
0245                          current_node == m_sink));
0246 
0247           if(get_tree(current_node) == tColorTraits::black()){
0248             //source tree growing
0249             out_edge_iterator ei, e_end;
0250             if(current_node != m_last_grow_vertex){
0251               m_last_grow_vertex = current_node;
0252               boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
0253             }
0254             for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it) {
0255               edge_descriptor out_edge = *m_last_grow_edge_it;
0256               if(get(m_res_cap_map, out_edge) > 0){ //check if we have capacity left on this edge
0257                 vertex_descriptor other_node = target(out_edge, m_g);
0258                 if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
0259                   set_tree(other_node, tColorTraits::black()); //acquire other node to our search tree
0260                   set_edge_to_parent(other_node, out_edge);   //set us as parent
0261                   put(m_dist_map, other_node, get(m_dist_map, current_node) + 1);  //and update the distance-heuristic
0262                   put(m_time_map, other_node, get(m_time_map, current_node));
0263                   add_active_node(other_node);
0264                 } else if(get_tree(other_node) == tColorTraits::black()) {
0265                   // we do this to get shorter paths. check if we are nearer to
0266                   // the source as its parent is
0267                   if(is_closer_to_terminal(current_node, other_node)){
0268                     set_edge_to_parent(other_node, out_edge);
0269                     put(m_dist_map, other_node, get(m_dist_map, current_node) + 1);
0270                     put(m_time_map, other_node, get(m_time_map, current_node));
0271                   }
0272                 } else{
0273                   BOOST_ASSERT(get_tree(other_node)==tColorTraits::white());
0274                   //kewl, found a path from one to the other search tree, return
0275                   // the connecting edge in src->sink dir
0276                   return std::make_pair(out_edge, true);
0277                 }
0278               }
0279             } //for all out-edges
0280           } //source-tree-growing
0281           else{
0282             BOOST_ASSERT(get_tree(current_node) == tColorTraits::white());
0283             out_edge_iterator ei, e_end;
0284             if(current_node != m_last_grow_vertex){
0285               m_last_grow_vertex = current_node;
0286               boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
0287             }
0288             for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){
0289               edge_descriptor in_edge = get(m_rev_edge_map, *m_last_grow_edge_it);
0290               if(get(m_res_cap_map, in_edge) > 0){ //check if there is capacity left
0291                 vertex_descriptor other_node = source(in_edge, m_g);
0292                 if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
0293                   set_tree(other_node, tColorTraits::white());      //acquire that node to our search tree
0294                   set_edge_to_parent(other_node, in_edge);          //set us as parent
0295                   add_active_node(other_node);                      //activate that node
0296                   put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); //set its distance
0297                   put(m_time_map, other_node, get(m_time_map, current_node));//and time
0298                 } else if(get_tree(other_node) == tColorTraits::white()){
0299                   if(is_closer_to_terminal(current_node, other_node)){
0300                     //we are closer to the sink than its parent is, so we "adopt" him
0301                     set_edge_to_parent(other_node, in_edge);
0302                     put(m_dist_map, other_node, get(m_dist_map, current_node) + 1);
0303                     put(m_time_map, other_node, get(m_time_map, current_node));
0304                   }
0305                 } else{
0306                   BOOST_ASSERT(get_tree(other_node)==tColorTraits::black());
0307                   //kewl, found a path from one to the other search tree,
0308                   // return the connecting edge in src->sink dir
0309                   return std::make_pair(in_edge, true);
0310                 }
0311               }
0312             } //for all out-edges
0313           } //sink-tree growing
0314 
0315           //all edges of that node are processed, and no more paths were found.
0316           // remove if from the front of the active queue
0317           finish_node(current_node);
0318         } //while active_nodes not empty
0319 
0320         //no active nodes anymore and no path found, we're done
0321         return std::make_pair(edge_descriptor(), false);
0322       }
0323 
0324       /**
0325        * augments path from s->t and updates residual graph
0326        * source(e, m_g) is the end of the path found in the source-tree
0327        * target(e, m_g) is the beginning of the path found in the sink-tree
0328        * this phase generates orphans on satured edges, if the attached verts are
0329        * from different search-trees orphans are ordered in distance to
0330        * sink/source. first the farest from the source are front_inserted into
0331        * the orphans list, and after that the sink-tree-orphans are
0332        * front_inserted. when going to adoption stage the orphans are popped_front,
0333        * and so we process the nearest verts to the terminals first
0334        */
0335       void augment(edge_descriptor e) {
0336         BOOST_ASSERT(get_tree(target(e, m_g)) == tColorTraits::white());
0337         BOOST_ASSERT(get_tree(source(e, m_g)) == tColorTraits::black());
0338         BOOST_ASSERT(m_orphans.empty());
0339 
0340         const tEdgeVal bottleneck = find_bottleneck(e);
0341         //now we push the found flow through the path
0342         //for each edge we saturate we have to look for the verts that belong to that edge, one of them becomes an orphans
0343         //now process the connecting edge
0344         put(m_res_cap_map, e, get(m_res_cap_map, e) - bottleneck);
0345         BOOST_ASSERT(get(m_res_cap_map, e) >= 0);
0346         put(m_res_cap_map, get(m_rev_edge_map, e), get(m_res_cap_map, get(m_rev_edge_map, e)) + bottleneck);
0347 
0348         //now we follow the path back to the source
0349         vertex_descriptor current_node = source(e, m_g);
0350         while(current_node != m_source){
0351           edge_descriptor pred = get_edge_to_parent(current_node);
0352           const tEdgeVal new_pred_cap = get(m_res_cap_map, pred) - bottleneck;
0353           put(m_res_cap_map, pred, new_pred_cap);
0354           BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
0355 
0356           const edge_descriptor pred_rev = get(m_rev_edge_map, pred);
0357           put(m_res_cap_map, pred_rev, get(m_res_cap_map, pred_rev) + bottleneck);
0358 
0359           if(new_pred_cap == 0){
0360             set_no_parent(current_node);
0361             m_orphans.push_front(current_node);
0362           }
0363           current_node = source(pred, m_g);
0364         }
0365         //then go forward in the sink-tree
0366         current_node = target(e, m_g);
0367         while(current_node != m_sink){
0368           edge_descriptor pred = get_edge_to_parent(current_node);
0369           const tEdgeVal new_pred_cap = get(m_res_cap_map, pred) - bottleneck;
0370           put(m_res_cap_map, pred, new_pred_cap);
0371           BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
0372 
0373           const edge_descriptor pred_rev = get(m_rev_edge_map, pred);
0374           put(m_res_cap_map, pred_rev, get(m_res_cap_map, pred_rev) + bottleneck);
0375 
0376           if(new_pred_cap == 0){
0377             set_no_parent(current_node);
0378             m_orphans.push_front(current_node);
0379           }
0380           current_node = target(pred, m_g);
0381         }
0382         //and add it to the max-flow
0383         m_flow += bottleneck;
0384       }
0385 
0386       /**
0387        * returns the bottleneck of a s->t path (end_of_path is last vertex in
0388        * source-tree, begin_of_path is first vertex in sink-tree)
0389        */
0390       inline tEdgeVal find_bottleneck(edge_descriptor e){
0391         BOOST_USING_STD_MIN();
0392         tEdgeVal minimum_cap = get(m_res_cap_map, e);
0393         vertex_descriptor current_node = source(e, m_g);
0394         //first go back in the source tree
0395         while(current_node != m_source){
0396           edge_descriptor pred = get_edge_to_parent(current_node);
0397           minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred));
0398           current_node = source(pred, m_g);
0399         }
0400         //then go forward in the sink-tree
0401         current_node = target(e, m_g);
0402         while(current_node != m_sink){
0403           edge_descriptor pred = get_edge_to_parent(current_node);
0404           minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred));
0405           current_node = target(pred, m_g);
0406         }
0407         return minimum_cap;
0408       }
0409 
0410       /**
0411        * rebuild search trees
0412        * empty the queue of orphans, and find new parents for them or just drop
0413        * them from the search trees
0414        */
0415       void adopt(){
0416         while(!m_orphans.empty() || !m_child_orphans.empty()){
0417           vertex_descriptor current_node;
0418           if(m_child_orphans.empty()){
0419             //get the next orphan from the main-queue  and remove it
0420             current_node = m_orphans.front();
0421             m_orphans.pop_front();
0422           } else{
0423             current_node = m_child_orphans.front();
0424             m_child_orphans.pop();
0425           }
0426           if(get_tree(current_node) == tColorTraits::black()){
0427             //we're in the source-tree
0428             tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
0429             edge_descriptor new_parent_edge;
0430             out_edge_iterator ei, e_end;
0431             for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
0432               const edge_descriptor in_edge = get(m_rev_edge_map, *ei);
0433               BOOST_ASSERT(target(in_edge, m_g) == current_node); //we should be the target of this edge
0434               if(get(m_res_cap_map, in_edge) > 0){
0435                 vertex_descriptor other_node = source(in_edge, m_g);
0436                 if(get_tree(other_node) == tColorTraits::black() && has_source_connect(other_node)){
0437                   if(get(m_dist_map, other_node) < min_distance){
0438                     min_distance = get(m_dist_map, other_node);
0439                     new_parent_edge = in_edge;
0440                   }
0441                 }
0442               }
0443             }
0444             if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
0445               set_edge_to_parent(current_node, new_parent_edge);
0446               put(m_dist_map, current_node, min_distance + 1);
0447               put(m_time_map, current_node, m_time);
0448             } else{
0449               put(m_time_map, current_node, 0);
0450               for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
0451                 edge_descriptor in_edge = get(m_rev_edge_map, *ei);
0452                 vertex_descriptor other_node = source(in_edge, m_g);
0453                 if(get_tree(other_node) == tColorTraits::black() && other_node != m_source){
0454                   if(get(m_res_cap_map, in_edge) > 0){
0455                     add_active_node(other_node);
0456                   }
0457                   if(has_parent(other_node) && source(get_edge_to_parent(other_node), m_g) == current_node){
0458                     //we are the parent of that node
0459                     //it has to find a new parent, too
0460                     set_no_parent(other_node);
0461                     m_child_orphans.push(other_node);
0462                   }
0463                 }
0464               }
0465               set_tree(current_node, tColorTraits::gray());
0466             } //no parent found
0467           } //source-tree-adoption
0468           else{
0469             //now we should be in the sink-tree, check that...
0470             BOOST_ASSERT(get_tree(current_node) == tColorTraits::white());
0471             out_edge_iterator ei, e_end;
0472             edge_descriptor new_parent_edge;
0473             tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
0474             for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
0475               const edge_descriptor out_edge = *ei;
0476               if(get(m_res_cap_map, out_edge) > 0){
0477                 const vertex_descriptor other_node = target(out_edge, m_g);
0478                 if(get_tree(other_node) == tColorTraits::white() && has_sink_connect(other_node))
0479                   if(get(m_dist_map, other_node) < min_distance){
0480                     min_distance = get(m_dist_map, other_node);
0481                     new_parent_edge = out_edge;
0482                   }
0483               }
0484             }
0485             if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
0486               set_edge_to_parent(current_node, new_parent_edge);
0487               put(m_dist_map, current_node, min_distance + 1);
0488               put(m_time_map, current_node, m_time);
0489             } else{
0490               put(m_time_map, current_node, 0);
0491               for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
0492                 const edge_descriptor out_edge = *ei;
0493                 const vertex_descriptor other_node = target(out_edge, m_g);
0494                 if(get_tree(other_node) == tColorTraits::white() && other_node != m_sink){
0495                   if(get(m_res_cap_map, out_edge) > 0){
0496                     add_active_node(other_node);
0497                   }
0498                   if(has_parent(other_node) && target(get_edge_to_parent(other_node), m_g) == current_node){
0499                     //we were it's parent, so it has to find a new one, too
0500                     set_no_parent(other_node);
0501                     m_child_orphans.push(other_node);
0502                   }
0503                 }
0504               }
0505               set_tree(current_node, tColorTraits::gray());
0506             } //no parent found
0507           } //sink-tree adoption
0508         } //while !orphans.empty()
0509       } //adopt
0510 
0511       /**
0512        * return next active vertex if there is one, otherwise a null_vertex
0513        */
0514       inline vertex_descriptor get_next_active_node(){
0515         while(true){
0516           if(m_active_nodes.empty())
0517             return graph_traits<Graph>::null_vertex();
0518           vertex_descriptor v = m_active_nodes.front();
0519 
0520       //if it has no parent, this node can't be active (if its not source or sink)
0521       if(!has_parent(v) && v != m_source && v != m_sink){
0522             m_active_nodes.pop();
0523             put(m_in_active_list_map, v, false);
0524           } else{
0525             BOOST_ASSERT(get_tree(v) == tColorTraits::black() || get_tree(v) == tColorTraits::white());
0526             return v;
0527           }
0528         }
0529       }
0530 
0531       /**
0532        * adds v as an active vertex, but only if its not in the list already
0533        */
0534       inline void add_active_node(vertex_descriptor v){
0535         BOOST_ASSERT(get_tree(v) != tColorTraits::gray());
0536         if(get(m_in_active_list_map, v)){
0537           if (m_last_grow_vertex == v) {
0538               m_last_grow_vertex = graph_traits<Graph>::null_vertex();
0539           }
0540           return;
0541         } else{
0542           put(m_in_active_list_map, v, true);
0543           m_active_nodes.push(v);
0544         }
0545       }
0546 
0547       /**
0548        * finish_node removes a node from the front of the active queue (its called in grow phase, if no more paths can be found using this node)
0549        */
0550       inline void finish_node(vertex_descriptor v){
0551         BOOST_ASSERT(m_active_nodes.front() == v);
0552         m_active_nodes.pop();
0553         put(m_in_active_list_map, v, false);
0554         m_last_grow_vertex = graph_traits<Graph>::null_vertex();
0555       }
0556 
0557       /**
0558        * removes a vertex from the queue of active nodes (actually this does nothing,
0559        * but checks if this node has no parent edge, as this is the criteria for
0560        * being no more active)
0561        */
0562       inline void remove_active_node(vertex_descriptor v){
0563         (void)v; // disable unused parameter warning
0564         BOOST_ASSERT(!has_parent(v));
0565       }
0566 
0567       /**
0568        * returns the search tree of v; tColorValue::black() for source tree,
0569        * white() for sink tree, gray() for no tree
0570        */
0571       inline tColorValue get_tree(vertex_descriptor v) const {
0572         return get(m_tree_map, v);
0573       }
0574 
0575       /**
0576        * sets search tree of v; tColorValue::black() for source tree, white()
0577        * for sink tree, gray() for no tree
0578        */
0579       inline void set_tree(vertex_descriptor v, tColorValue t){
0580         put(m_tree_map, v, t);
0581       }
0582 
0583       /**
0584        * returns edge to parent vertex of v;
0585        */
0586       inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const{
0587         return get(m_pre_map, v);
0588       }
0589 
0590       /**
0591        * returns true if the edge stored in m_pre_map[v] is a valid entry
0592        */
0593       inline bool has_parent(vertex_descriptor v) const{
0594         return get(m_has_parent_map, v);
0595       }
0596 
0597       /**
0598        * sets edge to parent vertex of v;
0599        */
0600       inline void set_edge_to_parent(vertex_descriptor v, edge_descriptor f_edge_to_parent){
0601         BOOST_ASSERT(get(m_res_cap_map, f_edge_to_parent) > 0);
0602         put(m_pre_map, v, f_edge_to_parent);
0603         put(m_has_parent_map, v, true);
0604       }
0605 
0606       /**
0607        * removes the edge to parent of v (this is done by invalidating the
0608        * entry an additional map)
0609        */
0610       inline void set_no_parent(vertex_descriptor v){
0611         put(m_has_parent_map, v, false);
0612       }
0613 
0614       /**
0615        * checks if vertex v has a connect to the sink-vertex (@p m_sink)
0616        * @param v the vertex which is checked
0617        * @return true if a path to the sink was found, false if not
0618        */
0619       inline bool has_sink_connect(vertex_descriptor v){
0620         tDistanceVal current_distance = 0;
0621         vertex_descriptor current_vertex = v;
0622         while(true){
0623           if(get(m_time_map, current_vertex) == m_time){
0624             //we found a node which was already checked this round. use it for distance calculations
0625             current_distance += get(m_dist_map, current_vertex);
0626             break;
0627           }
0628           if(current_vertex == m_sink){
0629             put(m_time_map, m_sink, m_time);
0630             break;
0631           }
0632           if(has_parent(current_vertex)){
0633             //it has a parent, so get it
0634             current_vertex = target(get_edge_to_parent(current_vertex), m_g);
0635             ++current_distance;
0636           } else{
0637             //no path found
0638             return false;
0639           }
0640         }
0641         current_vertex=v;
0642         while(get(m_time_map, current_vertex) != m_time){
0643           put(m_dist_map, current_vertex, current_distance);
0644           --current_distance;
0645           put(m_time_map, current_vertex, m_time);
0646           current_vertex = target(get_edge_to_parent(current_vertex), m_g);
0647         }
0648         return true;
0649       }
0650 
0651       /**
0652        * checks if vertex v has a connect to the source-vertex (@p m_source)
0653        * @param v the vertex which is checked
0654        * @return true if a path to the source was found, false if not
0655        */
0656       inline bool has_source_connect(vertex_descriptor v){
0657         tDistanceVal current_distance = 0;
0658         vertex_descriptor current_vertex = v;
0659         while(true){
0660           if(get(m_time_map, current_vertex) == m_time){
0661             //we found a node which was already checked this round. use it for distance calculations
0662             current_distance += get(m_dist_map, current_vertex);
0663             break;
0664           }
0665           if(current_vertex == m_source){
0666             put(m_time_map, m_source, m_time);
0667             break;
0668           }
0669           if(has_parent(current_vertex)){
0670             //it has a parent, so get it
0671             current_vertex = source(get_edge_to_parent(current_vertex), m_g);
0672             ++current_distance;
0673           } else{
0674             //no path found
0675             return false;
0676           }
0677         }
0678         current_vertex=v;
0679         while(get(m_time_map, current_vertex) != m_time){
0680             put(m_dist_map, current_vertex, current_distance);
0681             --current_distance;
0682             put(m_time_map, current_vertex, m_time);
0683             current_vertex = source(get_edge_to_parent(current_vertex), m_g);
0684         }
0685         return true;
0686       }
0687 
0688       /**
0689        * returns true, if p is closer to a terminal than q
0690        */
0691       inline bool is_closer_to_terminal(vertex_descriptor p, vertex_descriptor q){
0692         //checks the timestamps first, to build no cycles, and after that the real distance
0693         return (get(m_time_map, q) <= get(m_time_map, p) &&
0694                 get(m_dist_map, q) > get(m_dist_map, p)+1);
0695       }
0696 
0697       ////////
0698       // member vars
0699       ////////
0700       Graph& m_g;
0701       IndexMap m_index_map;
0702       EdgeCapacityMap m_cap_map;
0703       ResidualCapacityEdgeMap m_res_cap_map;
0704       ReverseEdgeMap m_rev_edge_map;
0705       PredecessorMap m_pre_map; //stores paths found in the growth stage
0706       ColorMap m_tree_map; //maps each vertex into one of the two search tree or none (gray())
0707       DistanceMap m_dist_map; //stores distance to source/sink nodes
0708       vertex_descriptor m_source;
0709       vertex_descriptor m_sink;
0710 
0711       tQueue m_active_nodes;
0712       std::vector<bool> m_in_active_list_vec;
0713       iterator_property_map<std::vector<bool>::iterator, IndexMap> m_in_active_list_map;
0714 
0715       std::list<vertex_descriptor> m_orphans;
0716       tQueue m_child_orphans; // we use a second queuqe for child orphans, as they are FIFO processed
0717 
0718       std::vector<bool> m_has_parent_vec;
0719       iterator_property_map<std::vector<bool>::iterator, IndexMap> m_has_parent_map;
0720 
0721       std::vector<long> m_time_vec; //timestamp of each node, used for sink/source-path calculations
0722       iterator_property_map<std::vector<long>::iterator, IndexMap> m_time_map;
0723       tEdgeVal m_flow;
0724       long m_time;
0725       vertex_descriptor m_last_grow_vertex;
0726       out_edge_iterator m_last_grow_edge_it;
0727       out_edge_iterator m_last_grow_edge_end;
0728 };
0729 
0730 } //namespace boost::detail
0731 
0732 /**
0733   * non-named-parameter version, given everything
0734   * this is the catch all version
0735   */
0736 template<class Graph,
0737          class CapacityEdgeMap,
0738          class ResidualCapacityEdgeMap,
0739          class ReverseEdgeMap, class PredecessorMap,
0740          class ColorMap,
0741          class DistanceMap,
0742          class IndexMap>
0743 typename property_traits<CapacityEdgeMap>::value_type
0744 boykov_kolmogorov_max_flow(Graph& g,
0745                            CapacityEdgeMap cap,
0746                            ResidualCapacityEdgeMap res_cap,
0747                            ReverseEdgeMap rev_map,
0748                            PredecessorMap pre_map,
0749                            ColorMap color,
0750                            DistanceMap dist,
0751                            IndexMap idx,
0752                            typename graph_traits<Graph>::vertex_descriptor src,
0753                            typename graph_traits<Graph>::vertex_descriptor sink)
0754 {
0755   typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
0756   typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
0757 
0758   //as this method is the last one before we instantiate the solver, we do the concept checks here
0759   BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> )); //to have vertices(), num_vertices(),
0760   BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<Graph> )); //to have edges()
0761   BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> )); //to have source(), target() and out_edges()
0762   BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<CapacityEdgeMap, edge_descriptor> )); //read flow-values from edges
0763   BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ResidualCapacityEdgeMap, edge_descriptor> )); //write flow-values to residuals
0764   BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<ReverseEdgeMap, edge_descriptor> )); //read out reverse edges
0765   BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<PredecessorMap, vertex_descriptor> )); //store predecessor there
0766   BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, vertex_descriptor> )); //write corresponding tree
0767   BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<DistanceMap, vertex_descriptor> )); //write distance to source/sink
0768   BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<IndexMap, vertex_descriptor> )); //get index 0...|V|-1
0769   BOOST_ASSERT(num_vertices(g) >= 2 && src != sink);
0770 
0771   detail::bk_max_flow<
0772     Graph, CapacityEdgeMap, ResidualCapacityEdgeMap, ReverseEdgeMap,
0773     PredecessorMap, ColorMap, DistanceMap, IndexMap
0774   > algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink);
0775 
0776   return algo.max_flow();
0777 }
0778 
0779 /**
0780  * non-named-parameter version, given capacity, residucal_capacity,
0781  * reverse_edges, and an index map.
0782  */
0783 template<class Graph,
0784          class CapacityEdgeMap,
0785          class ResidualCapacityEdgeMap,
0786          class ReverseEdgeMap,
0787          class IndexMap>
0788 typename property_traits<CapacityEdgeMap>::value_type
0789 boykov_kolmogorov_max_flow(Graph& g,
0790                            CapacityEdgeMap cap,
0791                            ResidualCapacityEdgeMap res_cap,
0792                            ReverseEdgeMap rev,
0793                            IndexMap idx,
0794                            typename graph_traits<Graph>::vertex_descriptor src,
0795                            typename graph_traits<Graph>::vertex_descriptor sink)
0796 {
0797   typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
0798   std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
0799   std::vector<default_color_type> color_vec(n_verts);
0800   std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
0801   return
0802     boykov_kolmogorov_max_flow(
0803       g, cap, res_cap, rev,
0804       make_iterator_property_map(predecessor_vec.begin(), idx),
0805       make_iterator_property_map(color_vec.begin(), idx),
0806       make_iterator_property_map(distance_vec.begin(), idx),
0807       idx, src, sink);
0808 }
0809 
0810 /**
0811  * non-named-parameter version, some given: capacity, residual_capacity,
0812  * reverse_edges, color_map and an index map. Use this if you are interested in
0813  * the minimum cut, as the color map provides that info.
0814  */
0815 template<class Graph,
0816          class CapacityEdgeMap,
0817          class ResidualCapacityEdgeMap,
0818          class ReverseEdgeMap,
0819          class ColorMap,
0820          class IndexMap>
0821 typename property_traits<CapacityEdgeMap>::value_type
0822 boykov_kolmogorov_max_flow(Graph& g,
0823                            CapacityEdgeMap cap,
0824                            ResidualCapacityEdgeMap res_cap,
0825                            ReverseEdgeMap rev,
0826                            ColorMap color,
0827                            IndexMap idx,
0828                            typename graph_traits<Graph>::vertex_descriptor src,
0829                            typename graph_traits<Graph>::vertex_descriptor sink)
0830 {
0831   typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
0832   std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
0833   std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
0834   return
0835     boykov_kolmogorov_max_flow(
0836       g, cap, res_cap, rev,
0837       make_iterator_property_map(predecessor_vec.begin(), idx),
0838       color,
0839       make_iterator_property_map(distance_vec.begin(), idx),
0840       idx, src, sink);
0841 }
0842 
0843 /**
0844  * named-parameter version, some given
0845  */
0846 template<class Graph, class P, class T, class R>
0847 typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
0848 boykov_kolmogorov_max_flow(Graph& g,
0849                            typename graph_traits<Graph>::vertex_descriptor src,
0850                            typename graph_traits<Graph>::vertex_descriptor sink,
0851                            const bgl_named_params<P, T, R>& params)
0852 {
0853   return
0854   boykov_kolmogorov_max_flow(
0855     g,
0856     choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
0857     choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity),
0858     choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
0859     choose_pmap(get_param(params, vertex_predecessor), g, vertex_predecessor),
0860     choose_pmap(get_param(params, vertex_color), g, vertex_color),
0861     choose_pmap(get_param(params, vertex_distance), g, vertex_distance),
0862     choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
0863     src, sink);
0864 }
0865 
0866 /**
0867  * named-parameter version, none given
0868  */
0869 template<class Graph>
0870 typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
0871 boykov_kolmogorov_max_flow(Graph& g,
0872                            typename graph_traits<Graph>::vertex_descriptor src,
0873                            typename graph_traits<Graph>::vertex_descriptor sink)
0874 {
0875   bgl_named_params<int, buffer_param_t> params(0); // bogus empty param
0876   return boykov_kolmogorov_max_flow(g, src, sink, params);
0877 }
0878 
0879 } // namespace boost
0880 
0881 #endif // BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
0882