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