Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:23

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 //    http://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 
0067 namespace detail
0068 {
0069 
0070     template < class Graph, class EdgeCapacityMap,
0071         class ResidualCapacityEdgeMap, class ReverseEdgeMap,
0072         class PredecessorMap, class ColorMap, class DistanceMap,
0073         class IndexMap >
0074     class bk_max_flow
0075     {
0076         typedef
0077             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 >
0085             tQueue; // queue of vertices, used in adoption-stage
0086         typedef typename property_traits< ColorMap >::value_type tColorValue;
0087         typedef color_traits< tColorValue > tColorTraits;
0088         typedef
0089             typename property_traits< DistanceMap >::value_type tDistanceVal;
0090 
0091     public:
0092         bk_max_flow(Graph& g, EdgeCapacityMap cap, ResidualCapacityEdgeMap res,
0093             ReverseEdgeMap rev, PredecessorMap pre, ColorMap color,
0094             DistanceMap dist, IndexMap idx, vertex_descriptor src,
0095             vertex_descriptor sink)
0096         : m_g(g)
0097         , m_index_map(idx)
0098         , m_cap_map(cap)
0099         , m_res_cap_map(res)
0100         , m_rev_edge_map(rev)
0101         , m_pre_map(pre)
0102         , m_tree_map(color)
0103         , m_dist_map(dist)
0104         , m_source(src)
0105         , m_sink(sink)
0106         , m_active_nodes()
0107         , m_in_active_list_vec(num_vertices(g), false)
0108         , m_in_active_list_map(make_iterator_property_map(
0109               m_in_active_list_vec.begin(), m_index_map))
0110         , m_has_parent_vec(num_vertices(g), false)
0111         , m_has_parent_map(
0112               make_iterator_property_map(m_has_parent_vec.begin(), m_index_map))
0113         , m_time_vec(num_vertices(g), 0)
0114         , m_time_map(
0115               make_iterator_property_map(m_time_vec.begin(), m_index_map))
0116         , m_flow(0)
0117         , m_time(1)
0118         , m_last_grow_vertex(graph_traits< Graph >::null_vertex())
0119         {
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             {
0124                 set_tree(*vi, tColorTraits::gray());
0125             }
0126             // Initialize flow to zero which means initializing
0127             // the residual capacity equal to the capacity
0128             edge_iterator ei, e_end;
0129             for (boost::tie(ei, e_end) = edges(m_g); ei != e_end; ++ei)
0130             {
0131                 put(m_res_cap_map, *ei, get(m_cap_map, *ei));
0132                 BOOST_ASSERT(get(m_rev_edge_map, get(m_rev_edge_map, *ei))
0133                     == *ei); // check if the reverse edge map is build up
0134                              // properly
0135             }
0136             // init the search trees with the two terminals
0137             set_tree(m_source, tColorTraits::black());
0138             set_tree(m_sink, tColorTraits::white());
0139             put(m_time_map, m_source, 1);
0140             put(m_time_map, m_sink, 1);
0141         }
0142 
0143         tEdgeVal max_flow()
0144         {
0145             // augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK
0146             augment_direct_paths();
0147             // start the main-loop
0148             while (true)
0149             {
0150                 bool path_found;
0151                 edge_descriptor connecting_edge;
0152                 boost::tie(connecting_edge, path_found)
0153                     = grow(); // find a path from source to sink
0154                 if (!path_found)
0155                 {
0156                     // we're finished, no more paths were found
0157                     break;
0158                 }
0159                 ++m_time;
0160                 augment(connecting_edge); // augment that path
0161                 adopt(); // rebuild search tree structure
0162             }
0163             return m_flow;
0164         }
0165 
0166         // the complete class is protected, as we want access to members in
0167         // derived test-class (see test/boykov_kolmogorov_max_flow_test.cpp)
0168     protected:
0169         void augment_direct_paths()
0170         {
0171             // in a first step, we augment all direct paths from
0172             // source->NODE->sink and additionally paths from source->sink. This
0173             // improves especially graphcuts for segmentation, as most of the
0174             // nodes have source/sink connects but shouldn't have an impact on
0175             // other maxflow problems (this is done in grow() anyway)
0176             out_edge_iterator ei, e_end;
0177             for (boost::tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end;
0178                  ++ei)
0179             {
0180                 edge_descriptor from_source = *ei;
0181                 vertex_descriptor current_node = target(from_source, m_g);
0182                 if (current_node == m_sink)
0183                 {
0184                     tEdgeVal cap = get(m_res_cap_map, from_source);
0185                     put(m_res_cap_map, from_source, 0);
0186                     m_flow += cap;
0187                     continue;
0188                 }
0189                 edge_descriptor to_sink;
0190                 bool is_there;
0191                 boost::tie(to_sink, is_there)
0192                     = lookup_edge(current_node, m_sink, m_g);
0193                 if (is_there)
0194                 {
0195                     tEdgeVal cap_from_source = get(m_res_cap_map, from_source);
0196                     tEdgeVal cap_to_sink = get(m_res_cap_map, to_sink);
0197                     if (cap_from_source > cap_to_sink)
0198                     {
0199                         set_tree(current_node, tColorTraits::black());
0200                         add_active_node(current_node);
0201                         set_edge_to_parent(current_node, from_source);
0202                         put(m_dist_map, current_node, 1);
0203                         put(m_time_map, current_node, 1);
0204                         // add stuff to flow and update residuals. we dont need
0205                         // to update reverse_edges, as incoming/outgoing edges
0206                         // to/from source/sink don't count for max-flow
0207                         put(m_res_cap_map, from_source,
0208                             get(m_res_cap_map, from_source) - cap_to_sink);
0209                         put(m_res_cap_map, to_sink, 0);
0210                         m_flow += cap_to_sink;
0211                     }
0212                     else if (cap_to_sink > 0)
0213                     {
0214                         set_tree(current_node, tColorTraits::white());
0215                         add_active_node(current_node);
0216                         set_edge_to_parent(current_node, to_sink);
0217                         put(m_dist_map, current_node, 1);
0218                         put(m_time_map, current_node, 1);
0219                         // add stuff to flow and update residuals. we dont need
0220                         // to update reverse_edges, as incoming/outgoing edges
0221                         // to/from source/sink don't count for max-flow
0222                         put(m_res_cap_map, to_sink,
0223                             get(m_res_cap_map, to_sink) - cap_from_source);
0224                         put(m_res_cap_map, from_source, 0);
0225                         m_flow += cap_from_source;
0226                     }
0227                 }
0228                 else if (get(m_res_cap_map, from_source))
0229                 {
0230                     // there is no sink connect, so we can't augment this path,
0231                     // but to avoid adding m_source to the active nodes, we just
0232                     // activate this node and set the approciate things
0233                     set_tree(current_node, tColorTraits::black());
0234                     set_edge_to_parent(current_node, from_source);
0235                     put(m_dist_map, current_node, 1);
0236                     put(m_time_map, current_node, 1);
0237                     add_active_node(current_node);
0238                 }
0239             }
0240             for (boost::tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end;
0241                  ++ei)
0242             {
0243                 edge_descriptor to_sink = get(m_rev_edge_map, *ei);
0244                 vertex_descriptor current_node = source(to_sink, m_g);
0245                 if (get(m_res_cap_map, to_sink))
0246                 {
0247                     set_tree(current_node, tColorTraits::white());
0248                     set_edge_to_parent(current_node, to_sink);
0249                     put(m_dist_map, current_node, 1);
0250                     put(m_time_map, current_node, 1);
0251                     add_active_node(current_node);
0252                 }
0253             }
0254         }
0255 
0256         /**
0257          * Returns a pair of an edge and a boolean. if the bool is true, the
0258          * edge is a connection of a found path from s->t , read "the link" and
0259          * source(returnVal, m_g) is the end of the path found in the
0260          * source-tree target(returnVal, m_g) is the beginning of the path found
0261          * in the sink-tree
0262          */
0263         std::pair< edge_descriptor, bool > grow()
0264         {
0265             BOOST_ASSERT(m_orphans.empty());
0266             vertex_descriptor current_node;
0267             while ((current_node = get_next_active_node())
0268                 != graph_traits< Graph >::null_vertex())
0269             { // if there is one
0270                 BOOST_ASSERT(get_tree(current_node) != tColorTraits::gray()
0271                     && (has_parent(current_node) || current_node == m_source
0272                         || current_node == m_sink));
0273 
0274                 if (get_tree(current_node) == tColorTraits::black())
0275                 {
0276                     // source tree growing
0277                     out_edge_iterator ei, e_end;
0278                     if (current_node != m_last_grow_vertex)
0279                     {
0280                         m_last_grow_vertex = current_node;
0281                         boost::tie(m_last_grow_edge_it, m_last_grow_edge_end)
0282                             = out_edges(current_node, m_g);
0283                     }
0284                     for (; m_last_grow_edge_it != m_last_grow_edge_end;
0285                          ++m_last_grow_edge_it)
0286                     {
0287                         edge_descriptor out_edge = *m_last_grow_edge_it;
0288                         if (get(m_res_cap_map, out_edge) > 0)
0289                         { // check if we have capacity left on this edge
0290                             vertex_descriptor other_node
0291                                 = target(out_edge, m_g);
0292                             if (get_tree(other_node) == tColorTraits::gray())
0293                             { // it's a free node
0294                                 set_tree(other_node,
0295                                     tColorTraits::black()); // aquire other node
0296                                                             // to our search
0297                                                             // tree
0298                                 set_edge_to_parent(
0299                                     other_node, out_edge); // set us as parent
0300                                 put(m_dist_map, other_node,
0301                                     get(m_dist_map, current_node)
0302                                         + 1); // and update the
0303                                               // distance-heuristic
0304                                 put(m_time_map, other_node,
0305                                     get(m_time_map, current_node));
0306                                 add_active_node(other_node);
0307                             }
0308                             else if (get_tree(other_node)
0309                                 == tColorTraits::black())
0310                             {
0311                                 // we do this to get shorter paths. check if we
0312                                 // are nearer to the source as its parent is
0313                                 if (is_closer_to_terminal(
0314                                         current_node, other_node))
0315                                 {
0316                                     set_edge_to_parent(other_node, out_edge);
0317                                     put(m_dist_map, other_node,
0318                                         get(m_dist_map, current_node) + 1);
0319                                     put(m_time_map, other_node,
0320                                         get(m_time_map, current_node));
0321                                 }
0322                             }
0323                             else
0324                             {
0325                                 BOOST_ASSERT(get_tree(other_node)
0326                                     == tColorTraits::white());
0327                                 // kewl, found a path from one to the other
0328                                 // search tree, return
0329                                 // the connecting edge in src->sink dir
0330                                 return std::make_pair(out_edge, true);
0331                             }
0332                         }
0333                     } // for all out-edges
0334                 } // source-tree-growing
0335                 else
0336                 {
0337                     BOOST_ASSERT(
0338                         get_tree(current_node) == tColorTraits::white());
0339                     out_edge_iterator ei, e_end;
0340                     if (current_node != m_last_grow_vertex)
0341                     {
0342                         m_last_grow_vertex = current_node;
0343                         boost::tie(m_last_grow_edge_it, m_last_grow_edge_end)
0344                             = out_edges(current_node, m_g);
0345                     }
0346                     for (; m_last_grow_edge_it != m_last_grow_edge_end;
0347                          ++m_last_grow_edge_it)
0348                     {
0349                         edge_descriptor in_edge
0350                             = get(m_rev_edge_map, *m_last_grow_edge_it);
0351                         if (get(m_res_cap_map, in_edge) > 0)
0352                         { // check if there is capacity left
0353                             vertex_descriptor other_node = source(in_edge, m_g);
0354                             if (get_tree(other_node) == tColorTraits::gray())
0355                             { // it's a free node
0356                                 set_tree(other_node,
0357                                     tColorTraits::white()); // aquire that node
0358                                                             // to our search
0359                                                             // tree
0360                                 set_edge_to_parent(
0361                                     other_node, in_edge); // set us as parent
0362                                 add_active_node(
0363                                     other_node); // activate that node
0364                                 put(m_dist_map, other_node,
0365                                     get(m_dist_map, current_node)
0366                                         + 1); // set its distance
0367                                 put(m_time_map, other_node,
0368                                     get(m_time_map, current_node)); // and time
0369                             }
0370                             else if (get_tree(other_node)
0371                                 == tColorTraits::white())
0372                             {
0373                                 if (is_closer_to_terminal(
0374                                         current_node, other_node))
0375                                 {
0376                                     // we are closer to the sink than its parent
0377                                     // is, so we "adopt" him
0378                                     set_edge_to_parent(other_node, in_edge);
0379                                     put(m_dist_map, other_node,
0380                                         get(m_dist_map, current_node) + 1);
0381                                     put(m_time_map, other_node,
0382                                         get(m_time_map, current_node));
0383                                 }
0384                             }
0385                             else
0386                             {
0387                                 BOOST_ASSERT(get_tree(other_node)
0388                                     == tColorTraits::black());
0389                                 // kewl, found a path from one to the other
0390                                 // search tree,
0391                                 // return the connecting edge in src->sink dir
0392                                 return std::make_pair(in_edge, true);
0393                             }
0394                         }
0395                     } // for all out-edges
0396                 } // sink-tree growing
0397 
0398                 // all edges of that node are processed, and no more paths were
0399                 // found.
0400                 // remove if from the front of the active queue
0401                 finish_node(current_node);
0402             } // while active_nodes not empty
0403 
0404             // no active nodes anymore and no path found, we're done
0405             return std::make_pair(edge_descriptor(), false);
0406         }
0407 
0408         /**
0409          * augments path from s->t and updates residual graph
0410          * source(e, m_g) is the end of the path found in the source-tree
0411          * target(e, m_g) is the beginning of the path found in the sink-tree
0412          * this phase generates orphans on satured edges, if the attached verts
0413          * are from different search-trees orphans are ordered in distance to
0414          * sink/source. first the farest from the source are front_inserted into
0415          * the orphans list, and after that the sink-tree-orphans are
0416          * front_inserted. when going to adoption stage the orphans are
0417          * popped_front, and so we process the nearest verts to the terminals
0418          * first
0419          */
0420         void augment(edge_descriptor e)
0421         {
0422             BOOST_ASSERT(get_tree(target(e, m_g)) == tColorTraits::white());
0423             BOOST_ASSERT(get_tree(source(e, m_g)) == tColorTraits::black());
0424             BOOST_ASSERT(m_orphans.empty());
0425 
0426             const tEdgeVal bottleneck = find_bottleneck(e);
0427             // now we push the found flow through the path
0428             // for each edge we saturate we have to look for the verts that
0429             // belong to that edge, one of them becomes an orphans now process
0430             // the connecting edge
0431             put(m_res_cap_map, e, get(m_res_cap_map, e) - bottleneck);
0432             BOOST_ASSERT(get(m_res_cap_map, e) >= 0);
0433             put(m_res_cap_map, get(m_rev_edge_map, e),
0434                 get(m_res_cap_map, get(m_rev_edge_map, e)) + bottleneck);
0435 
0436             // now we follow the path back to the source
0437             vertex_descriptor current_node = source(e, m_g);
0438             while (current_node != m_source)
0439             {
0440                 edge_descriptor pred = get_edge_to_parent(current_node);
0441                 put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck);
0442                 BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
0443                 put(m_res_cap_map, get(m_rev_edge_map, pred),
0444                     get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck);
0445                 if (get(m_res_cap_map, pred) == 0)
0446                 {
0447                     set_no_parent(current_node);
0448                     m_orphans.push_front(current_node);
0449                 }
0450                 current_node = source(pred, m_g);
0451             }
0452             // then go forward in the sink-tree
0453             current_node = target(e, m_g);
0454             while (current_node != m_sink)
0455             {
0456                 edge_descriptor pred = get_edge_to_parent(current_node);
0457                 put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck);
0458                 BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
0459                 put(m_res_cap_map, get(m_rev_edge_map, pred),
0460                     get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck);
0461                 if (get(m_res_cap_map, pred) == 0)
0462                 {
0463                     set_no_parent(current_node);
0464                     m_orphans.push_front(current_node);
0465                 }
0466                 current_node = target(pred, m_g);
0467             }
0468             // and add it to the max-flow
0469             m_flow += bottleneck;
0470         }
0471 
0472         /**
0473          * returns the bottleneck of a s->t path (end_of_path is last vertex in
0474          * source-tree, begin_of_path is first vertex in sink-tree)
0475          */
0476         inline tEdgeVal find_bottleneck(edge_descriptor e)
0477         {
0478             BOOST_USING_STD_MIN();
0479             tEdgeVal minimum_cap = get(m_res_cap_map, e);
0480             vertex_descriptor current_node = source(e, m_g);
0481             // first go back in the source tree
0482             while (current_node != m_source)
0483             {
0484                 edge_descriptor pred = get_edge_to_parent(current_node);
0485                 minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0486                     minimum_cap, get(m_res_cap_map, pred));
0487                 current_node = source(pred, m_g);
0488             }
0489             // then go forward in the sink-tree
0490             current_node = target(e, m_g);
0491             while (current_node != m_sink)
0492             {
0493                 edge_descriptor pred = get_edge_to_parent(current_node);
0494                 minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0495                     minimum_cap, get(m_res_cap_map, pred));
0496                 current_node = target(pred, m_g);
0497             }
0498             return minimum_cap;
0499         }
0500 
0501         /**
0502          * rebuild search trees
0503          * empty the queue of orphans, and find new parents for them or just
0504          * drop them from the search trees
0505          */
0506         void adopt()
0507         {
0508             while (!m_orphans.empty() || !m_child_orphans.empty())
0509             {
0510                 vertex_descriptor current_node;
0511                 if (m_child_orphans.empty())
0512                 {
0513                     // get the next orphan from the main-queue  and remove it
0514                     current_node = m_orphans.front();
0515                     m_orphans.pop_front();
0516                 }
0517                 else
0518                 {
0519                     current_node = m_child_orphans.front();
0520                     m_child_orphans.pop();
0521                 }
0522                 if (get_tree(current_node) == tColorTraits::black())
0523                 {
0524                     // we're in the source-tree
0525                     tDistanceVal min_distance
0526                         = (std::numeric_limits< tDistanceVal >::max)();
0527                     edge_descriptor new_parent_edge;
0528                     out_edge_iterator ei, e_end;
0529                     for (boost::tie(ei, e_end) = out_edges(current_node, m_g);
0530                          ei != e_end; ++ei)
0531                     {
0532                         const edge_descriptor in_edge
0533                             = get(m_rev_edge_map, *ei);
0534                         BOOST_ASSERT(target(in_edge, m_g)
0535                             == current_node); // we should be the target of this
0536                                               // edge
0537                         if (get(m_res_cap_map, in_edge) > 0)
0538                         {
0539                             vertex_descriptor other_node = source(in_edge, m_g);
0540                             if (get_tree(other_node) == tColorTraits::black()
0541                                 && has_source_connect(other_node))
0542                             {
0543                                 if (get(m_dist_map, other_node) < min_distance)
0544                                 {
0545                                     min_distance = get(m_dist_map, other_node);
0546                                     new_parent_edge = in_edge;
0547                                 }
0548                             }
0549                         }
0550                     }
0551                     if (min_distance
0552                         != (std::numeric_limits< tDistanceVal >::max)())
0553                     {
0554                         set_edge_to_parent(current_node, new_parent_edge);
0555                         put(m_dist_map, current_node, min_distance + 1);
0556                         put(m_time_map, current_node, m_time);
0557                     }
0558                     else
0559                     {
0560                         put(m_time_map, current_node, 0);
0561                         for (boost::tie(ei, e_end)
0562                              = out_edges(current_node, m_g);
0563                              ei != e_end; ++ei)
0564                         {
0565                             edge_descriptor in_edge = get(m_rev_edge_map, *ei);
0566                             vertex_descriptor other_node = source(in_edge, m_g);
0567                             if (get_tree(other_node) == tColorTraits::black()
0568                                 && other_node != m_source)
0569                             {
0570                                 if (get(m_res_cap_map, in_edge) > 0)
0571                                 {
0572                                     add_active_node(other_node);
0573                                 }
0574                                 if (has_parent(other_node)
0575                                     && source(
0576                                            get_edge_to_parent(other_node), m_g)
0577                                         == current_node)
0578                                 {
0579                                     // we are the parent of that node
0580                                     // it has to find a new parent, too
0581                                     set_no_parent(other_node);
0582                                     m_child_orphans.push(other_node);
0583                                 }
0584                             }
0585                         }
0586                         set_tree(current_node, tColorTraits::gray());
0587                     } // no parent found
0588                 } // source-tree-adoption
0589                 else
0590                 {
0591                     // now we should be in the sink-tree, check that...
0592                     BOOST_ASSERT(
0593                         get_tree(current_node) == tColorTraits::white());
0594                     out_edge_iterator ei, e_end;
0595                     edge_descriptor new_parent_edge;
0596                     tDistanceVal min_distance
0597                         = (std::numeric_limits< tDistanceVal >::max)();
0598                     for (boost::tie(ei, e_end) = out_edges(current_node, m_g);
0599                          ei != e_end; ++ei)
0600                     {
0601                         const edge_descriptor out_edge = *ei;
0602                         if (get(m_res_cap_map, out_edge) > 0)
0603                         {
0604                             const vertex_descriptor other_node
0605                                 = target(out_edge, m_g);
0606                             if (get_tree(other_node) == tColorTraits::white()
0607                                 && has_sink_connect(other_node))
0608                                 if (get(m_dist_map, other_node) < min_distance)
0609                                 {
0610                                     min_distance = get(m_dist_map, other_node);
0611                                     new_parent_edge = out_edge;
0612                                 }
0613                         }
0614                     }
0615                     if (min_distance
0616                         != (std::numeric_limits< tDistanceVal >::max)())
0617                     {
0618                         set_edge_to_parent(current_node, new_parent_edge);
0619                         put(m_dist_map, current_node, min_distance + 1);
0620                         put(m_time_map, current_node, m_time);
0621                     }
0622                     else
0623                     {
0624                         put(m_time_map, current_node, 0);
0625                         for (boost::tie(ei, e_end)
0626                              = out_edges(current_node, m_g);
0627                              ei != e_end; ++ei)
0628                         {
0629                             const edge_descriptor out_edge = *ei;
0630                             const vertex_descriptor other_node
0631                                 = target(out_edge, m_g);
0632                             if (get_tree(other_node) == tColorTraits::white()
0633                                 && other_node != m_sink)
0634                             {
0635                                 if (get(m_res_cap_map, out_edge) > 0)
0636                                 {
0637                                     add_active_node(other_node);
0638                                 }
0639                                 if (has_parent(other_node)
0640                                     && target(
0641                                            get_edge_to_parent(other_node), m_g)
0642                                         == current_node)
0643                                 {
0644                                     // we were it's parent, so it has to find a
0645                                     // new one, too
0646                                     set_no_parent(other_node);
0647                                     m_child_orphans.push(other_node);
0648                                 }
0649                             }
0650                         }
0651                         set_tree(current_node, tColorTraits::gray());
0652                     } // no parent found
0653                 } // sink-tree adoption
0654             } // while !orphans.empty()
0655         } // adopt
0656 
0657         /**
0658          * return next active vertex if there is one, otherwise a null_vertex
0659          */
0660         inline vertex_descriptor get_next_active_node()
0661         {
0662             while (true)
0663             {
0664                 if (m_active_nodes.empty())
0665                     return graph_traits< Graph >::null_vertex();
0666                 vertex_descriptor v = m_active_nodes.front();
0667 
0668                 // if it has no parent, this node can't be active (if its not
0669                 // source or sink)
0670                 if (!has_parent(v) && v != m_source && v != m_sink)
0671                 {
0672                     m_active_nodes.pop();
0673                     put(m_in_active_list_map, v, false);
0674                 }
0675                 else
0676                 {
0677                     BOOST_ASSERT(get_tree(v) == tColorTraits::black()
0678                         || get_tree(v) == tColorTraits::white());
0679                     return v;
0680                 }
0681             }
0682         }
0683 
0684         /**
0685          * adds v as an active vertex, but only if its not in the list already
0686          */
0687         inline void add_active_node(vertex_descriptor v)
0688         {
0689             BOOST_ASSERT(get_tree(v) != tColorTraits::gray());
0690             if (get(m_in_active_list_map, v))
0691             {
0692                 if (m_last_grow_vertex == v)
0693                 {
0694                     m_last_grow_vertex = graph_traits< Graph >::null_vertex();
0695                 }
0696                 return;
0697             }
0698             else
0699             {
0700                 put(m_in_active_list_map, v, true);
0701                 m_active_nodes.push(v);
0702             }
0703         }
0704 
0705         /**
0706          * finish_node removes a node from the front of the active queue (its
0707          * called in grow phase, if no more paths can be found using this node)
0708          */
0709         inline void finish_node(vertex_descriptor v)
0710         {
0711             BOOST_ASSERT(m_active_nodes.front() == v);
0712             m_active_nodes.pop();
0713             put(m_in_active_list_map, v, false);
0714             m_last_grow_vertex = graph_traits< Graph >::null_vertex();
0715         }
0716 
0717         /**
0718          * removes a vertex from the queue of active nodes (actually this does
0719          * nothing, but checks if this node has no parent edge, as this is the
0720          * criteria for being no more active)
0721          */
0722         inline void remove_active_node(vertex_descriptor v)
0723         {
0724             BOOST_ASSERT(!has_parent(v));
0725         }
0726 
0727         /**
0728          * returns the search tree of v; tColorValue::black() for source tree,
0729          * white() for sink tree, gray() for no tree
0730          */
0731         inline tColorValue get_tree(vertex_descriptor v) const
0732         {
0733             return get(m_tree_map, v);
0734         }
0735 
0736         /**
0737          * sets search tree of v; tColorValue::black() for source tree, white()
0738          * for sink tree, gray() for no tree
0739          */
0740         inline void set_tree(vertex_descriptor v, tColorValue t)
0741         {
0742             put(m_tree_map, v, t);
0743         }
0744 
0745         /**
0746          * returns edge to parent vertex of v;
0747          */
0748         inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const
0749         {
0750             return get(m_pre_map, v);
0751         }
0752 
0753         /**
0754          * returns true if the edge stored in m_pre_map[v] is a valid entry
0755          */
0756         inline bool has_parent(vertex_descriptor v) const
0757         {
0758             return get(m_has_parent_map, v);
0759         }
0760 
0761         /**
0762          * sets edge to parent vertex of v;
0763          */
0764         inline void set_edge_to_parent(
0765             vertex_descriptor v, edge_descriptor f_edge_to_parent)
0766         {
0767             BOOST_ASSERT(get(m_res_cap_map, f_edge_to_parent) > 0);
0768             put(m_pre_map, v, f_edge_to_parent);
0769             put(m_has_parent_map, v, true);
0770         }
0771 
0772         /**
0773          * removes the edge to parent of v (this is done by invalidating the
0774          * entry an additional map)
0775          */
0776         inline void set_no_parent(vertex_descriptor v)
0777         {
0778             put(m_has_parent_map, v, false);
0779         }
0780 
0781         /**
0782          * checks if vertex v has a connect to the sink-vertex (@var m_sink)
0783          * @param v the vertex which is checked
0784          * @return true if a path to the sink was found, false if not
0785          */
0786         inline bool has_sink_connect(vertex_descriptor v)
0787         {
0788             tDistanceVal current_distance = 0;
0789             vertex_descriptor current_vertex = v;
0790             while (true)
0791             {
0792                 if (get(m_time_map, current_vertex) == m_time)
0793                 {
0794                     // we found a node which was already checked this round. use
0795                     // it for distance calculations
0796                     current_distance += get(m_dist_map, current_vertex);
0797                     break;
0798                 }
0799                 if (current_vertex == m_sink)
0800                 {
0801                     put(m_time_map, m_sink, m_time);
0802                     break;
0803                 }
0804                 if (has_parent(current_vertex))
0805                 {
0806                     // it has a parent, so get it
0807                     current_vertex
0808                         = target(get_edge_to_parent(current_vertex), m_g);
0809                     ++current_distance;
0810                 }
0811                 else
0812                 {
0813                     // no path found
0814                     return false;
0815                 }
0816             }
0817             current_vertex = v;
0818             while (get(m_time_map, current_vertex) != m_time)
0819             {
0820                 put(m_dist_map, current_vertex, current_distance);
0821                 --current_distance;
0822                 put(m_time_map, current_vertex, m_time);
0823                 current_vertex
0824                     = target(get_edge_to_parent(current_vertex), m_g);
0825             }
0826             return true;
0827         }
0828 
0829         /**
0830          * checks if vertex v has a connect to the source-vertex (@var m_source)
0831          * @param v the vertex which is checked
0832          * @return true if a path to the source was found, false if not
0833          */
0834         inline bool has_source_connect(vertex_descriptor v)
0835         {
0836             tDistanceVal current_distance = 0;
0837             vertex_descriptor current_vertex = v;
0838             while (true)
0839             {
0840                 if (get(m_time_map, current_vertex) == m_time)
0841                 {
0842                     // we found a node which was already checked this round. use
0843                     // it for distance calculations
0844                     current_distance += get(m_dist_map, current_vertex);
0845                     break;
0846                 }
0847                 if (current_vertex == m_source)
0848                 {
0849                     put(m_time_map, m_source, m_time);
0850                     break;
0851                 }
0852                 if (has_parent(current_vertex))
0853                 {
0854                     // it has a parent, so get it
0855                     current_vertex
0856                         = source(get_edge_to_parent(current_vertex), m_g);
0857                     ++current_distance;
0858                 }
0859                 else
0860                 {
0861                     // no path found
0862                     return false;
0863                 }
0864             }
0865             current_vertex = v;
0866             while (get(m_time_map, current_vertex) != m_time)
0867             {
0868                 put(m_dist_map, current_vertex, current_distance);
0869                 --current_distance;
0870                 put(m_time_map, current_vertex, m_time);
0871                 current_vertex
0872                     = source(get_edge_to_parent(current_vertex), m_g);
0873             }
0874             return true;
0875         }
0876 
0877         /**
0878          * returns true, if p is closer to a terminal than q
0879          */
0880         inline bool is_closer_to_terminal(
0881             vertex_descriptor p, vertex_descriptor q)
0882         {
0883             // checks the timestamps first, to build no cycles, and after that
0884             // the real distance
0885             return (get(m_time_map, q) <= get(m_time_map, p)
0886                 && get(m_dist_map, q) > get(m_dist_map, p) + 1);
0887         }
0888 
0889         ////////
0890         // member vars
0891         ////////
0892         Graph& m_g;
0893         IndexMap m_index_map;
0894         EdgeCapacityMap m_cap_map;
0895         ResidualCapacityEdgeMap m_res_cap_map;
0896         ReverseEdgeMap m_rev_edge_map;
0897         PredecessorMap m_pre_map; // stores paths found in the growth stage
0898         ColorMap m_tree_map; // maps each vertex into one of the two search tree
0899                              // or none (gray())
0900         DistanceMap m_dist_map; // stores distance to source/sink nodes
0901         vertex_descriptor m_source;
0902         vertex_descriptor m_sink;
0903 
0904         tQueue m_active_nodes;
0905         std::vector< bool > m_in_active_list_vec;
0906         iterator_property_map< std::vector< bool >::iterator, IndexMap >
0907             m_in_active_list_map;
0908 
0909         std::list< vertex_descriptor > m_orphans;
0910         tQueue m_child_orphans; // we use a second queuqe for child orphans, as
0911                                 // they are FIFO processed
0912 
0913         std::vector< bool > m_has_parent_vec;
0914         iterator_property_map< std::vector< bool >::iterator, IndexMap >
0915             m_has_parent_map;
0916 
0917         std::vector< long > m_time_vec; // timestamp of each node, used for
0918                                         // sink/source-path calculations
0919         iterator_property_map< std::vector< long >::iterator, IndexMap >
0920             m_time_map;
0921         tEdgeVal m_flow;
0922         long m_time;
0923         vertex_descriptor m_last_grow_vertex;
0924         out_edge_iterator m_last_grow_edge_it;
0925         out_edge_iterator m_last_grow_edge_end;
0926     };
0927 
0928 } // namespace boost::detail
0929 
0930 /**
0931  * non-named-parameter version, given everything
0932  * this is the catch all version
0933  */
0934 template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap,
0935     class ReverseEdgeMap, class PredecessorMap, class ColorMap,
0936     class DistanceMap, class IndexMap >
0937 typename property_traits< CapacityEdgeMap >::value_type
0938 boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap,
0939     ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev_map,
0940     PredecessorMap pre_map, ColorMap color, DistanceMap dist, IndexMap idx,
0941     typename graph_traits< Graph >::vertex_descriptor src,
0942     typename graph_traits< Graph >::vertex_descriptor sink)
0943 {
0944     typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor;
0945     typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor;
0946 
0947     // as this method is the last one before we instantiate the solver, we do
0948     // the concept checks here
0949     BOOST_CONCEPT_ASSERT(
0950         (VertexListGraphConcept< Graph >)); // to have vertices(),
0951                                             // num_vertices(),
0952     BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >)); // to have edges()
0953     BOOST_CONCEPT_ASSERT(
0954         (IncidenceGraphConcept< Graph >)); // to have source(), target() and
0955                                            // out_edges()
0956     BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< CapacityEdgeMap,
0957         edge_descriptor >)); // read flow-values from edges
0958     BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ResidualCapacityEdgeMap,
0959         edge_descriptor >)); // write flow-values to residuals
0960     BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< ReverseEdgeMap,
0961         edge_descriptor >)); // read out reverse edges
0962     BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< PredecessorMap,
0963         vertex_descriptor >)); // store predecessor there
0964     BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ColorMap,
0965         vertex_descriptor >)); // write corresponding tree
0966     BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< DistanceMap,
0967         vertex_descriptor >)); // write distance to source/sink
0968     BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< IndexMap,
0969         vertex_descriptor >)); // get index 0...|V|-1
0970     BOOST_ASSERT(num_vertices(g) >= 2 && src != sink);
0971 
0972     detail::bk_max_flow< Graph, CapacityEdgeMap, ResidualCapacityEdgeMap,
0973         ReverseEdgeMap, PredecessorMap, ColorMap, DistanceMap, IndexMap >
0974         algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink);
0975 
0976     return algo.max_flow();
0977 }
0978 
0979 /**
0980  * non-named-parameter version, given capacity, residual_capacity,
0981  * reverse_edges, and an index map.
0982  */
0983 template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap,
0984     class ReverseEdgeMap, class IndexMap >
0985 typename property_traits< CapacityEdgeMap >::value_type
0986 boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap,
0987     ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev, IndexMap idx,
0988     typename graph_traits< Graph >::vertex_descriptor src,
0989     typename graph_traits< Graph >::vertex_descriptor sink)
0990 {
0991     typename graph_traits< Graph >::vertices_size_type n_verts
0992         = num_vertices(g);
0993     std::vector< typename graph_traits< Graph >::edge_descriptor >
0994         predecessor_vec(n_verts);
0995     std::vector< default_color_type > color_vec(n_verts);
0996     std::vector< typename graph_traits< Graph >::vertices_size_type >
0997         distance_vec(n_verts);
0998     return boykov_kolmogorov_max_flow(g, cap, res_cap, rev,
0999         make_iterator_property_map(predecessor_vec.begin(), idx),
1000         make_iterator_property_map(color_vec.begin(), idx),
1001         make_iterator_property_map(distance_vec.begin(), idx), idx, src, sink);
1002 }
1003 
1004 /**
1005  * non-named-parameter version, some given: capacity, residual_capacity,
1006  * reverse_edges, color_map and an index map. Use this if you are interested in
1007  * the minimum cut, as the color map provides that info.
1008  */
1009 template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap,
1010     class ReverseEdgeMap, class ColorMap, class IndexMap >
1011 typename property_traits< CapacityEdgeMap >::value_type
1012 boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap,
1013     ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev, ColorMap color,
1014     IndexMap idx, typename graph_traits< Graph >::vertex_descriptor src,
1015     typename graph_traits< Graph >::vertex_descriptor sink)
1016 {
1017     typename graph_traits< Graph >::vertices_size_type n_verts
1018         = num_vertices(g);
1019     std::vector< typename graph_traits< Graph >::edge_descriptor >
1020         predecessor_vec(n_verts);
1021     std::vector< typename graph_traits< Graph >::vertices_size_type >
1022         distance_vec(n_verts);
1023     return boykov_kolmogorov_max_flow(g, cap, res_cap, rev,
1024         make_iterator_property_map(predecessor_vec.begin(), idx), color,
1025         make_iterator_property_map(distance_vec.begin(), idx), idx, src, sink);
1026 }
1027 
1028 /**
1029  * named-parameter version, some given
1030  */
1031 template < class Graph, class P, class T, class R >
1032 typename detail::edge_capacity_value< Graph, P, T, R >::type
1033 boykov_kolmogorov_max_flow(Graph& g,
1034     typename graph_traits< Graph >::vertex_descriptor src,
1035     typename graph_traits< Graph >::vertex_descriptor sink,
1036     const bgl_named_params< P, T, R >& params)
1037 {
1038     return boykov_kolmogorov_max_flow(g,
1039         choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
1040         choose_pmap(get_param(params, edge_residual_capacity), g,
1041             edge_residual_capacity),
1042         choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
1043         choose_pmap(
1044             get_param(params, vertex_predecessor), g, vertex_predecessor),
1045         choose_pmap(get_param(params, vertex_color), g, vertex_color),
1046         choose_pmap(get_param(params, vertex_distance), g, vertex_distance),
1047         choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
1048         src, sink);
1049 }
1050 
1051 /**
1052  * named-parameter version, none given
1053  */
1054 template < class Graph >
1055 typename property_traits<
1056     typename property_map< Graph, edge_capacity_t >::const_type >::value_type
1057 boykov_kolmogorov_max_flow(Graph& g,
1058     typename graph_traits< Graph >::vertex_descriptor src,
1059     typename graph_traits< Graph >::vertex_descriptor sink)
1060 {
1061     bgl_named_params< int, buffer_param_t > params(0); // bogus empty param
1062     return boykov_kolmogorov_max_flow(g, src, sink, params);
1063 }
1064 
1065 } // namespace boost
1066 
1067 #endif // BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP