annotate DEPENDENCIES/generic/include/boost/graph/boykov_kolmogorov_max_flow.hpp @ 118:770eb830ec19 emscripten

Typo fix
author Chris Cannam
date Wed, 18 May 2016 16:14:08 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright (c) 2006, Stephan Diederich
Chris@16 2 //
Chris@16 3 // This code may be used under either of the following two licences:
Chris@16 4 //
Chris@16 5 // Permission is hereby granted, free of charge, to any person
Chris@16 6 // obtaining a copy of this software and associated documentation
Chris@16 7 // files (the "Software"), to deal in the Software without
Chris@16 8 // restriction, including without limitation the rights to use,
Chris@16 9 // copy, modify, merge, publish, distribute, sublicense, and/or
Chris@16 10 // sell copies of the Software, and to permit persons to whom the
Chris@16 11 // Software is furnished to do so, subject to the following
Chris@16 12 // conditions:
Chris@16 13 //
Chris@16 14 // The above copyright notice and this permission notice shall be
Chris@16 15 // included in all copies or substantial portions of the Software.
Chris@16 16 //
Chris@16 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@16 18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
Chris@16 19 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@16 20 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
Chris@16 21 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
Chris@16 22 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Chris@16 23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
Chris@16 24 // OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
Chris@16 25 //
Chris@16 26 // Or:
Chris@16 27 //
Chris@16 28 // Distributed under the Boost Software License, Version 1.0.
Chris@16 29 // (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 30 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 31
Chris@16 32 #ifndef BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
Chris@16 33 #define BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
Chris@16 34
Chris@16 35 #include <boost/config.hpp>
Chris@16 36 #include <boost/assert.hpp>
Chris@16 37 #include <vector>
Chris@16 38 #include <list>
Chris@16 39 #include <utility>
Chris@16 40 #include <iosfwd>
Chris@16 41 #include <algorithm> // for std::min and std::max
Chris@16 42
Chris@16 43 #include <boost/pending/queue.hpp>
Chris@16 44 #include <boost/limits.hpp>
Chris@16 45 #include <boost/property_map/property_map.hpp>
Chris@16 46 #include <boost/none_t.hpp>
Chris@16 47 #include <boost/graph/graph_concepts.hpp>
Chris@16 48 #include <boost/graph/named_function_params.hpp>
Chris@16 49 #include <boost/graph/lookup_edge.hpp>
Chris@16 50 #include <boost/concept/assert.hpp>
Chris@16 51
Chris@16 52 // The algorithm impelemented here is described in:
Chris@16 53 //
Chris@16 54 // Boykov, Y., Kolmogorov, V. "An Experimental Comparison of Min-Cut/Max-Flow
Chris@16 55 // Algorithms for Energy Minimization in Vision", In IEEE Transactions on
Chris@16 56 // Pattern Analysis and Machine Intelligence, vol. 26, no. 9, pp. 1124-1137,
Chris@16 57 // Sep 2004.
Chris@16 58 //
Chris@16 59 // For further reading, also see:
Chris@16 60 //
Chris@16 61 // Kolmogorov, V. "Graph Based Algorithms for Scene Reconstruction from Two or
Chris@16 62 // More Views". PhD thesis, Cornell University, Sep 2003.
Chris@16 63
Chris@16 64 namespace boost {
Chris@16 65
Chris@16 66 namespace detail {
Chris@16 67
Chris@16 68 template <class Graph,
Chris@16 69 class EdgeCapacityMap,
Chris@16 70 class ResidualCapacityEdgeMap,
Chris@16 71 class ReverseEdgeMap,
Chris@16 72 class PredecessorMap,
Chris@16 73 class ColorMap,
Chris@16 74 class DistanceMap,
Chris@16 75 class IndexMap>
Chris@16 76 class bk_max_flow {
Chris@16 77 typedef typename property_traits<EdgeCapacityMap>::value_type tEdgeVal;
Chris@16 78 typedef graph_traits<Graph> tGraphTraits;
Chris@16 79 typedef typename tGraphTraits::vertex_iterator vertex_iterator;
Chris@16 80 typedef typename tGraphTraits::vertex_descriptor vertex_descriptor;
Chris@16 81 typedef typename tGraphTraits::edge_descriptor edge_descriptor;
Chris@16 82 typedef typename tGraphTraits::edge_iterator edge_iterator;
Chris@16 83 typedef typename tGraphTraits::out_edge_iterator out_edge_iterator;
Chris@16 84 typedef boost::queue<vertex_descriptor> tQueue; //queue of vertices, used in adoption-stage
Chris@16 85 typedef typename property_traits<ColorMap>::value_type tColorValue;
Chris@16 86 typedef color_traits<tColorValue> tColorTraits;
Chris@16 87 typedef typename property_traits<DistanceMap>::value_type tDistanceVal;
Chris@16 88
Chris@16 89 public:
Chris@16 90 bk_max_flow(Graph& g,
Chris@16 91 EdgeCapacityMap cap,
Chris@16 92 ResidualCapacityEdgeMap res,
Chris@16 93 ReverseEdgeMap rev,
Chris@16 94 PredecessorMap pre,
Chris@16 95 ColorMap color,
Chris@16 96 DistanceMap dist,
Chris@16 97 IndexMap idx,
Chris@16 98 vertex_descriptor src,
Chris@16 99 vertex_descriptor sink):
Chris@16 100 m_g(g),
Chris@16 101 m_index_map(idx),
Chris@16 102 m_cap_map(cap),
Chris@16 103 m_res_cap_map(res),
Chris@16 104 m_rev_edge_map(rev),
Chris@16 105 m_pre_map(pre),
Chris@16 106 m_tree_map(color),
Chris@16 107 m_dist_map(dist),
Chris@16 108 m_source(src),
Chris@16 109 m_sink(sink),
Chris@16 110 m_active_nodes(),
Chris@16 111 m_in_active_list_vec(num_vertices(g), false),
Chris@16 112 m_in_active_list_map(make_iterator_property_map(m_in_active_list_vec.begin(), m_index_map)),
Chris@16 113 m_has_parent_vec(num_vertices(g), false),
Chris@16 114 m_has_parent_map(make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)),
Chris@16 115 m_time_vec(num_vertices(g), 0),
Chris@16 116 m_time_map(make_iterator_property_map(m_time_vec.begin(), m_index_map)),
Chris@16 117 m_flow(0),
Chris@16 118 m_time(1),
Chris@16 119 m_last_grow_vertex(graph_traits<Graph>::null_vertex()){
Chris@16 120 // initialize the color-map with gray-values
Chris@16 121 vertex_iterator vi, v_end;
Chris@16 122 for(boost::tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi){
Chris@16 123 set_tree(*vi, tColorTraits::gray());
Chris@16 124 }
Chris@16 125 // Initialize flow to zero which means initializing
Chris@16 126 // the residual capacity equal to the capacity
Chris@16 127 edge_iterator ei, e_end;
Chris@16 128 for(boost::tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) {
Chris@16 129 put(m_res_cap_map, *ei, get(m_cap_map, *ei));
Chris@16 130 BOOST_ASSERT(get(m_rev_edge_map, get(m_rev_edge_map, *ei)) == *ei); //check if the reverse edge map is build up properly
Chris@16 131 }
Chris@16 132 //init the search trees with the two terminals
Chris@16 133 set_tree(m_source, tColorTraits::black());
Chris@16 134 set_tree(m_sink, tColorTraits::white());
Chris@16 135 put(m_time_map, m_source, 1);
Chris@16 136 put(m_time_map, m_sink, 1);
Chris@16 137 }
Chris@16 138
Chris@16 139 tEdgeVal max_flow(){
Chris@16 140 //augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK
Chris@16 141 augment_direct_paths();
Chris@16 142 //start the main-loop
Chris@16 143 while(true){
Chris@16 144 bool path_found;
Chris@16 145 edge_descriptor connecting_edge;
Chris@16 146 boost::tie(connecting_edge, path_found) = grow(); //find a path from source to sink
Chris@16 147 if(!path_found){
Chris@16 148 //we're finished, no more paths were found
Chris@16 149 break;
Chris@16 150 }
Chris@16 151 ++m_time;
Chris@16 152 augment(connecting_edge); //augment that path
Chris@16 153 adopt(); //rebuild search tree structure
Chris@16 154 }
Chris@16 155 return m_flow;
Chris@16 156 }
Chris@16 157
Chris@16 158 // the complete class is protected, as we want access to members in
Chris@16 159 // derived test-class (see test/boykov_kolmogorov_max_flow_test.cpp)
Chris@16 160 protected:
Chris@16 161 void augment_direct_paths(){
Chris@16 162 // in a first step, we augment all direct paths from source->NODE->sink
Chris@16 163 // and additionally paths from source->sink. This improves especially
Chris@16 164 // graphcuts for segmentation, as most of the nodes have source/sink
Chris@16 165 // connects but shouldn't have an impact on other maxflow problems
Chris@16 166 // (this is done in grow() anyway)
Chris@16 167 out_edge_iterator ei, e_end;
Chris@16 168 for(boost::tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei){
Chris@16 169 edge_descriptor from_source = *ei;
Chris@16 170 vertex_descriptor current_node = target(from_source, m_g);
Chris@16 171 if(current_node == m_sink){
Chris@16 172 tEdgeVal cap = get(m_res_cap_map, from_source);
Chris@16 173 put(m_res_cap_map, from_source, 0);
Chris@16 174 m_flow += cap;
Chris@16 175 continue;
Chris@16 176 }
Chris@16 177 edge_descriptor to_sink;
Chris@16 178 bool is_there;
Chris@16 179 boost::tie(to_sink, is_there) = lookup_edge(current_node, m_sink, m_g);
Chris@16 180 if(is_there){
Chris@16 181 tEdgeVal cap_from_source = get(m_res_cap_map, from_source);
Chris@16 182 tEdgeVal cap_to_sink = get(m_res_cap_map, to_sink);
Chris@16 183 if(cap_from_source > cap_to_sink){
Chris@16 184 set_tree(current_node, tColorTraits::black());
Chris@16 185 add_active_node(current_node);
Chris@16 186 set_edge_to_parent(current_node, from_source);
Chris@16 187 put(m_dist_map, current_node, 1);
Chris@16 188 put(m_time_map, current_node, 1);
Chris@16 189 // add stuff to flow and update residuals. we dont need to
Chris@16 190 // update reverse_edges, as incoming/outgoing edges to/from
Chris@16 191 // source/sink don't count for max-flow
Chris@16 192 put(m_res_cap_map, from_source, get(m_res_cap_map, from_source) - cap_to_sink);
Chris@16 193 put(m_res_cap_map, to_sink, 0);
Chris@16 194 m_flow += cap_to_sink;
Chris@16 195 } else if(cap_to_sink > 0){
Chris@16 196 set_tree(current_node, tColorTraits::white());
Chris@16 197 add_active_node(current_node);
Chris@16 198 set_edge_to_parent(current_node, to_sink);
Chris@16 199 put(m_dist_map, current_node, 1);
Chris@16 200 put(m_time_map, current_node, 1);
Chris@16 201 // add stuff to flow and update residuals. we dont need to update
Chris@16 202 // reverse_edges, as incoming/outgoing edges to/from source/sink
Chris@16 203 // don't count for max-flow
Chris@16 204 put(m_res_cap_map, to_sink, get(m_res_cap_map, to_sink) - cap_from_source);
Chris@16 205 put(m_res_cap_map, from_source, 0);
Chris@16 206 m_flow += cap_from_source;
Chris@16 207 }
Chris@16 208 } else if(get(m_res_cap_map, from_source)){
Chris@16 209 // there is no sink connect, so we can't augment this path, but to
Chris@16 210 // avoid adding m_source to the active nodes, we just activate this
Chris@16 211 // node and set the approciate things
Chris@16 212 set_tree(current_node, tColorTraits::black());
Chris@16 213 set_edge_to_parent(current_node, from_source);
Chris@16 214 put(m_dist_map, current_node, 1);
Chris@16 215 put(m_time_map, current_node, 1);
Chris@16 216 add_active_node(current_node);
Chris@16 217 }
Chris@16 218 }
Chris@16 219 for(boost::tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei){
Chris@16 220 edge_descriptor to_sink = get(m_rev_edge_map, *ei);
Chris@16 221 vertex_descriptor current_node = source(to_sink, m_g);
Chris@16 222 if(get(m_res_cap_map, to_sink)){
Chris@16 223 set_tree(current_node, tColorTraits::white());
Chris@16 224 set_edge_to_parent(current_node, to_sink);
Chris@16 225 put(m_dist_map, current_node, 1);
Chris@16 226 put(m_time_map, current_node, 1);
Chris@16 227 add_active_node(current_node);
Chris@16 228 }
Chris@16 229 }
Chris@16 230 }
Chris@16 231
Chris@16 232 /**
Chris@16 233 * Returns a pair of an edge and a boolean. if the bool is true, the
Chris@16 234 * edge is a connection of a found path from s->t , read "the link" and
Chris@16 235 * source(returnVal, m_g) is the end of the path found in the source-tree
Chris@16 236 * target(returnVal, m_g) is the beginning of the path found in the sink-tree
Chris@16 237 */
Chris@16 238 std::pair<edge_descriptor, bool> grow(){
Chris@16 239 BOOST_ASSERT(m_orphans.empty());
Chris@16 240 vertex_descriptor current_node;
Chris@16 241 while((current_node = get_next_active_node()) != graph_traits<Graph>::null_vertex()){ //if there is one
Chris@16 242 BOOST_ASSERT(get_tree(current_node) != tColorTraits::gray() &&
Chris@16 243 (has_parent(current_node) ||
Chris@16 244 current_node == m_source ||
Chris@16 245 current_node == m_sink));
Chris@16 246
Chris@16 247 if(get_tree(current_node) == tColorTraits::black()){
Chris@16 248 //source tree growing
Chris@16 249 out_edge_iterator ei, e_end;
Chris@16 250 if(current_node != m_last_grow_vertex){
Chris@16 251 m_last_grow_vertex = current_node;
Chris@16 252 boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
Chris@16 253 }
Chris@16 254 for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it) {
Chris@16 255 edge_descriptor out_edge = *m_last_grow_edge_it;
Chris@16 256 if(get(m_res_cap_map, out_edge) > 0){ //check if we have capacity left on this edge
Chris@16 257 vertex_descriptor other_node = target(out_edge, m_g);
Chris@16 258 if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
Chris@16 259 set_tree(other_node, tColorTraits::black()); //aquire other node to our search tree
Chris@16 260 set_edge_to_parent(other_node, out_edge); //set us as parent
Chris@16 261 put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); //and update the distance-heuristic
Chris@16 262 put(m_time_map, other_node, get(m_time_map, current_node));
Chris@16 263 add_active_node(other_node);
Chris@16 264 } else if(get_tree(other_node) == tColorTraits::black()) {
Chris@16 265 // we do this to get shorter paths. check if we are nearer to
Chris@16 266 // the source as its parent is
Chris@16 267 if(is_closer_to_terminal(current_node, other_node)){
Chris@16 268 set_edge_to_parent(other_node, out_edge);
Chris@16 269 put(m_dist_map, other_node, get(m_dist_map, current_node) + 1);
Chris@16 270 put(m_time_map, other_node, get(m_time_map, current_node));
Chris@16 271 }
Chris@16 272 } else{
Chris@16 273 BOOST_ASSERT(get_tree(other_node)==tColorTraits::white());
Chris@16 274 //kewl, found a path from one to the other search tree, return
Chris@16 275 // the connecting edge in src->sink dir
Chris@16 276 return std::make_pair(out_edge, true);
Chris@16 277 }
Chris@16 278 }
Chris@16 279 } //for all out-edges
Chris@16 280 } //source-tree-growing
Chris@16 281 else{
Chris@16 282 BOOST_ASSERT(get_tree(current_node) == tColorTraits::white());
Chris@16 283 out_edge_iterator ei, e_end;
Chris@16 284 if(current_node != m_last_grow_vertex){
Chris@16 285 m_last_grow_vertex = current_node;
Chris@16 286 boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
Chris@16 287 }
Chris@16 288 for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){
Chris@16 289 edge_descriptor in_edge = get(m_rev_edge_map, *m_last_grow_edge_it);
Chris@16 290 if(get(m_res_cap_map, in_edge) > 0){ //check if there is capacity left
Chris@16 291 vertex_descriptor other_node = source(in_edge, m_g);
Chris@16 292 if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
Chris@16 293 set_tree(other_node, tColorTraits::white()); //aquire that node to our search tree
Chris@16 294 set_edge_to_parent(other_node, in_edge); //set us as parent
Chris@16 295 add_active_node(other_node); //activate that node
Chris@16 296 put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); //set its distance
Chris@16 297 put(m_time_map, other_node, get(m_time_map, current_node));//and time
Chris@16 298 } else if(get_tree(other_node) == tColorTraits::white()){
Chris@16 299 if(is_closer_to_terminal(current_node, other_node)){
Chris@16 300 //we are closer to the sink than its parent is, so we "adopt" him
Chris@16 301 set_edge_to_parent(other_node, in_edge);
Chris@16 302 put(m_dist_map, other_node, get(m_dist_map, current_node) + 1);
Chris@16 303 put(m_time_map, other_node, get(m_time_map, current_node));
Chris@16 304 }
Chris@16 305 } else{
Chris@16 306 BOOST_ASSERT(get_tree(other_node)==tColorTraits::black());
Chris@16 307 //kewl, found a path from one to the other search tree,
Chris@16 308 // return the connecting edge in src->sink dir
Chris@16 309 return std::make_pair(in_edge, true);
Chris@16 310 }
Chris@16 311 }
Chris@16 312 } //for all out-edges
Chris@16 313 } //sink-tree growing
Chris@16 314
Chris@16 315 //all edges of that node are processed, and no more paths were found.
Chris@16 316 // remove if from the front of the active queue
Chris@16 317 finish_node(current_node);
Chris@16 318 } //while active_nodes not empty
Chris@16 319
Chris@16 320 //no active nodes anymore and no path found, we're done
Chris@16 321 return std::make_pair(edge_descriptor(), false);
Chris@16 322 }
Chris@16 323
Chris@16 324 /**
Chris@16 325 * augments path from s->t and updates residual graph
Chris@16 326 * source(e, m_g) is the end of the path found in the source-tree
Chris@16 327 * target(e, m_g) is the beginning of the path found in the sink-tree
Chris@16 328 * this phase generates orphans on satured edges, if the attached verts are
Chris@16 329 * from different search-trees orphans are ordered in distance to
Chris@16 330 * sink/source. first the farest from the source are front_inserted into
Chris@16 331 * the orphans list, and after that the sink-tree-orphans are
Chris@16 332 * front_inserted. when going to adoption stage the orphans are popped_front,
Chris@16 333 * and so we process the nearest verts to the terminals first
Chris@16 334 */
Chris@16 335 void augment(edge_descriptor e) {
Chris@16 336 BOOST_ASSERT(get_tree(target(e, m_g)) == tColorTraits::white());
Chris@16 337 BOOST_ASSERT(get_tree(source(e, m_g)) == tColorTraits::black());
Chris@16 338 BOOST_ASSERT(m_orphans.empty());
Chris@16 339
Chris@16 340 const tEdgeVal bottleneck = find_bottleneck(e);
Chris@16 341 //now we push the found flow through the path
Chris@16 342 //for each edge we saturate we have to look for the verts that belong to that edge, one of them becomes an orphans
Chris@16 343 //now process the connecting edge
Chris@16 344 put(m_res_cap_map, e, get(m_res_cap_map, e) - bottleneck);
Chris@16 345 BOOST_ASSERT(get(m_res_cap_map, e) >= 0);
Chris@16 346 put(m_res_cap_map, get(m_rev_edge_map, e), get(m_res_cap_map, get(m_rev_edge_map, e)) + bottleneck);
Chris@16 347
Chris@16 348 //now we follow the path back to the source
Chris@16 349 vertex_descriptor current_node = source(e, m_g);
Chris@16 350 while(current_node != m_source){
Chris@16 351 edge_descriptor pred = get_edge_to_parent(current_node);
Chris@16 352 put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck);
Chris@16 353 BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
Chris@16 354 put(m_res_cap_map, get(m_rev_edge_map, pred), get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck);
Chris@16 355 if(get(m_res_cap_map, pred) == 0){
Chris@16 356 set_no_parent(current_node);
Chris@16 357 m_orphans.push_front(current_node);
Chris@16 358 }
Chris@16 359 current_node = source(pred, m_g);
Chris@16 360 }
Chris@16 361 //then go forward in the sink-tree
Chris@16 362 current_node = target(e, m_g);
Chris@16 363 while(current_node != m_sink){
Chris@16 364 edge_descriptor pred = get_edge_to_parent(current_node);
Chris@16 365 put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck);
Chris@16 366 BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
Chris@16 367 put(m_res_cap_map, get(m_rev_edge_map, pred), get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck);
Chris@16 368 if(get(m_res_cap_map, pred) == 0){
Chris@16 369 set_no_parent(current_node);
Chris@16 370 m_orphans.push_front(current_node);
Chris@16 371 }
Chris@16 372 current_node = target(pred, m_g);
Chris@16 373 }
Chris@16 374 //and add it to the max-flow
Chris@16 375 m_flow += bottleneck;
Chris@16 376 }
Chris@16 377
Chris@16 378 /**
Chris@16 379 * returns the bottleneck of a s->t path (end_of_path is last vertex in
Chris@16 380 * source-tree, begin_of_path is first vertex in sink-tree)
Chris@16 381 */
Chris@16 382 inline tEdgeVal find_bottleneck(edge_descriptor e){
Chris@16 383 BOOST_USING_STD_MIN();
Chris@16 384 tEdgeVal minimum_cap = get(m_res_cap_map, e);
Chris@16 385 vertex_descriptor current_node = source(e, m_g);
Chris@16 386 //first go back in the source tree
Chris@16 387 while(current_node != m_source){
Chris@16 388 edge_descriptor pred = get_edge_to_parent(current_node);
Chris@16 389 minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred));
Chris@16 390 current_node = source(pred, m_g);
Chris@16 391 }
Chris@16 392 //then go forward in the sink-tree
Chris@16 393 current_node = target(e, m_g);
Chris@16 394 while(current_node != m_sink){
Chris@16 395 edge_descriptor pred = get_edge_to_parent(current_node);
Chris@16 396 minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred));
Chris@16 397 current_node = target(pred, m_g);
Chris@16 398 }
Chris@16 399 return minimum_cap;
Chris@16 400 }
Chris@16 401
Chris@16 402 /**
Chris@16 403 * rebuild search trees
Chris@16 404 * empty the queue of orphans, and find new parents for them or just drop
Chris@16 405 * them from the search trees
Chris@16 406 */
Chris@16 407 void adopt(){
Chris@16 408 while(!m_orphans.empty() || !m_child_orphans.empty()){
Chris@16 409 vertex_descriptor current_node;
Chris@16 410 if(m_child_orphans.empty()){
Chris@16 411 //get the next orphan from the main-queue and remove it
Chris@16 412 current_node = m_orphans.front();
Chris@16 413 m_orphans.pop_front();
Chris@16 414 } else{
Chris@16 415 current_node = m_child_orphans.front();
Chris@16 416 m_child_orphans.pop();
Chris@16 417 }
Chris@16 418 if(get_tree(current_node) == tColorTraits::black()){
Chris@16 419 //we're in the source-tree
Chris@16 420 tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
Chris@16 421 edge_descriptor new_parent_edge;
Chris@16 422 out_edge_iterator ei, e_end;
Chris@16 423 for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
Chris@16 424 const edge_descriptor in_edge = get(m_rev_edge_map, *ei);
Chris@16 425 BOOST_ASSERT(target(in_edge, m_g) == current_node); //we should be the target of this edge
Chris@16 426 if(get(m_res_cap_map, in_edge) > 0){
Chris@16 427 vertex_descriptor other_node = source(in_edge, m_g);
Chris@16 428 if(get_tree(other_node) == tColorTraits::black() && has_source_connect(other_node)){
Chris@16 429 if(get(m_dist_map, other_node) < min_distance){
Chris@16 430 min_distance = get(m_dist_map, other_node);
Chris@16 431 new_parent_edge = in_edge;
Chris@16 432 }
Chris@16 433 }
Chris@16 434 }
Chris@16 435 }
Chris@16 436 if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
Chris@16 437 set_edge_to_parent(current_node, new_parent_edge);
Chris@16 438 put(m_dist_map, current_node, min_distance + 1);
Chris@16 439 put(m_time_map, current_node, m_time);
Chris@16 440 } else{
Chris@16 441 put(m_time_map, current_node, 0);
Chris@16 442 for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
Chris@16 443 edge_descriptor in_edge = get(m_rev_edge_map, *ei);
Chris@16 444 vertex_descriptor other_node = source(in_edge, m_g);
Chris@16 445 if(get_tree(other_node) == tColorTraits::black() && other_node != m_source){
Chris@16 446 if(get(m_res_cap_map, in_edge) > 0){
Chris@16 447 add_active_node(other_node);
Chris@16 448 }
Chris@16 449 if(has_parent(other_node) && source(get_edge_to_parent(other_node), m_g) == current_node){
Chris@16 450 //we are the parent of that node
Chris@16 451 //it has to find a new parent, too
Chris@16 452 set_no_parent(other_node);
Chris@16 453 m_child_orphans.push(other_node);
Chris@16 454 }
Chris@16 455 }
Chris@16 456 }
Chris@16 457 set_tree(current_node, tColorTraits::gray());
Chris@16 458 } //no parent found
Chris@16 459 } //source-tree-adoption
Chris@16 460 else{
Chris@16 461 //now we should be in the sink-tree, check that...
Chris@16 462 BOOST_ASSERT(get_tree(current_node) == tColorTraits::white());
Chris@16 463 out_edge_iterator ei, e_end;
Chris@16 464 edge_descriptor new_parent_edge;
Chris@16 465 tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
Chris@16 466 for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
Chris@16 467 const edge_descriptor out_edge = *ei;
Chris@16 468 if(get(m_res_cap_map, out_edge) > 0){
Chris@16 469 const vertex_descriptor other_node = target(out_edge, m_g);
Chris@16 470 if(get_tree(other_node) == tColorTraits::white() && has_sink_connect(other_node))
Chris@16 471 if(get(m_dist_map, other_node) < min_distance){
Chris@16 472 min_distance = get(m_dist_map, other_node);
Chris@16 473 new_parent_edge = out_edge;
Chris@16 474 }
Chris@16 475 }
Chris@16 476 }
Chris@16 477 if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
Chris@16 478 set_edge_to_parent(current_node, new_parent_edge);
Chris@16 479 put(m_dist_map, current_node, min_distance + 1);
Chris@16 480 put(m_time_map, current_node, m_time);
Chris@16 481 } else{
Chris@16 482 put(m_time_map, current_node, 0);
Chris@16 483 for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
Chris@16 484 const edge_descriptor out_edge = *ei;
Chris@16 485 const vertex_descriptor other_node = target(out_edge, m_g);
Chris@16 486 if(get_tree(other_node) == tColorTraits::white() && other_node != m_sink){
Chris@16 487 if(get(m_res_cap_map, out_edge) > 0){
Chris@16 488 add_active_node(other_node);
Chris@16 489 }
Chris@16 490 if(has_parent(other_node) && target(get_edge_to_parent(other_node), m_g) == current_node){
Chris@16 491 //we were it's parent, so it has to find a new one, too
Chris@16 492 set_no_parent(other_node);
Chris@16 493 m_child_orphans.push(other_node);
Chris@16 494 }
Chris@16 495 }
Chris@16 496 }
Chris@16 497 set_tree(current_node, tColorTraits::gray());
Chris@16 498 } //no parent found
Chris@16 499 } //sink-tree adoption
Chris@16 500 } //while !orphans.empty()
Chris@16 501 } //adopt
Chris@16 502
Chris@16 503 /**
Chris@16 504 * return next active vertex if there is one, otherwise a null_vertex
Chris@16 505 */
Chris@16 506 inline vertex_descriptor get_next_active_node(){
Chris@16 507 while(true){
Chris@16 508 if(m_active_nodes.empty())
Chris@16 509 return graph_traits<Graph>::null_vertex();
Chris@16 510 vertex_descriptor v = m_active_nodes.front();
Chris@16 511
Chris@16 512 //if it has no parent, this node can't be active (if its not source or sink)
Chris@16 513 if(!has_parent(v) && v != m_source && v != m_sink){
Chris@16 514 m_active_nodes.pop();
Chris@16 515 put(m_in_active_list_map, v, false);
Chris@16 516 } else{
Chris@16 517 BOOST_ASSERT(get_tree(v) == tColorTraits::black() || get_tree(v) == tColorTraits::white());
Chris@16 518 return v;
Chris@16 519 }
Chris@16 520 }
Chris@16 521 }
Chris@16 522
Chris@16 523 /**
Chris@16 524 * adds v as an active vertex, but only if its not in the list already
Chris@16 525 */
Chris@16 526 inline void add_active_node(vertex_descriptor v){
Chris@16 527 BOOST_ASSERT(get_tree(v) != tColorTraits::gray());
Chris@16 528 if(get(m_in_active_list_map, v)){
Chris@16 529 if (m_last_grow_vertex == v) {
Chris@16 530 m_last_grow_vertex = graph_traits<Graph>::null_vertex();
Chris@16 531 }
Chris@16 532 return;
Chris@16 533 } else{
Chris@16 534 put(m_in_active_list_map, v, true);
Chris@16 535 m_active_nodes.push(v);
Chris@16 536 }
Chris@16 537 }
Chris@16 538
Chris@16 539 /**
Chris@16 540 * 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)
Chris@16 541 */
Chris@16 542 inline void finish_node(vertex_descriptor v){
Chris@16 543 BOOST_ASSERT(m_active_nodes.front() == v);
Chris@16 544 m_active_nodes.pop();
Chris@16 545 put(m_in_active_list_map, v, false);
Chris@16 546 m_last_grow_vertex = graph_traits<Graph>::null_vertex();
Chris@16 547 }
Chris@16 548
Chris@16 549 /**
Chris@16 550 * removes a vertex from the queue of active nodes (actually this does nothing,
Chris@16 551 * but checks if this node has no parent edge, as this is the criteria for
Chris@16 552 * being no more active)
Chris@16 553 */
Chris@16 554 inline void remove_active_node(vertex_descriptor v){
Chris@16 555 BOOST_ASSERT(!has_parent(v));
Chris@16 556 }
Chris@16 557
Chris@16 558 /**
Chris@16 559 * returns the search tree of v; tColorValue::black() for source tree,
Chris@16 560 * white() for sink tree, gray() for no tree
Chris@16 561 */
Chris@16 562 inline tColorValue get_tree(vertex_descriptor v) const {
Chris@16 563 return get(m_tree_map, v);
Chris@16 564 }
Chris@16 565
Chris@16 566 /**
Chris@16 567 * sets search tree of v; tColorValue::black() for source tree, white()
Chris@16 568 * for sink tree, gray() for no tree
Chris@16 569 */
Chris@16 570 inline void set_tree(vertex_descriptor v, tColorValue t){
Chris@16 571 put(m_tree_map, v, t);
Chris@16 572 }
Chris@16 573
Chris@16 574 /**
Chris@16 575 * returns edge to parent vertex of v;
Chris@16 576 */
Chris@16 577 inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const{
Chris@16 578 return get(m_pre_map, v);
Chris@16 579 }
Chris@16 580
Chris@16 581 /**
Chris@16 582 * returns true if the edge stored in m_pre_map[v] is a valid entry
Chris@16 583 */
Chris@16 584 inline bool has_parent(vertex_descriptor v) const{
Chris@16 585 return get(m_has_parent_map, v);
Chris@16 586 }
Chris@16 587
Chris@16 588 /**
Chris@16 589 * sets edge to parent vertex of v;
Chris@16 590 */
Chris@16 591 inline void set_edge_to_parent(vertex_descriptor v, edge_descriptor f_edge_to_parent){
Chris@16 592 BOOST_ASSERT(get(m_res_cap_map, f_edge_to_parent) > 0);
Chris@16 593 put(m_pre_map, v, f_edge_to_parent);
Chris@16 594 put(m_has_parent_map, v, true);
Chris@16 595 }
Chris@16 596
Chris@16 597 /**
Chris@16 598 * removes the edge to parent of v (this is done by invalidating the
Chris@16 599 * entry an additional map)
Chris@16 600 */
Chris@16 601 inline void set_no_parent(vertex_descriptor v){
Chris@16 602 put(m_has_parent_map, v, false);
Chris@16 603 }
Chris@16 604
Chris@16 605 /**
Chris@16 606 * checks if vertex v has a connect to the sink-vertex (@var m_sink)
Chris@16 607 * @param v the vertex which is checked
Chris@16 608 * @return true if a path to the sink was found, false if not
Chris@16 609 */
Chris@16 610 inline bool has_sink_connect(vertex_descriptor v){
Chris@16 611 tDistanceVal current_distance = 0;
Chris@16 612 vertex_descriptor current_vertex = v;
Chris@16 613 while(true){
Chris@16 614 if(get(m_time_map, current_vertex) == m_time){
Chris@16 615 //we found a node which was already checked this round. use it for distance calculations
Chris@16 616 current_distance += get(m_dist_map, current_vertex);
Chris@16 617 break;
Chris@16 618 }
Chris@16 619 if(current_vertex == m_sink){
Chris@16 620 put(m_time_map, m_sink, m_time);
Chris@16 621 break;
Chris@16 622 }
Chris@16 623 if(has_parent(current_vertex)){
Chris@16 624 //it has a parent, so get it
Chris@16 625 current_vertex = target(get_edge_to_parent(current_vertex), m_g);
Chris@16 626 ++current_distance;
Chris@16 627 } else{
Chris@16 628 //no path found
Chris@16 629 return false;
Chris@16 630 }
Chris@16 631 }
Chris@16 632 current_vertex=v;
Chris@16 633 while(get(m_time_map, current_vertex) != m_time){
Chris@16 634 put(m_dist_map, current_vertex, current_distance);
Chris@16 635 --current_distance;
Chris@16 636 put(m_time_map, current_vertex, m_time);
Chris@16 637 current_vertex = target(get_edge_to_parent(current_vertex), m_g);
Chris@16 638 }
Chris@16 639 return true;
Chris@16 640 }
Chris@16 641
Chris@16 642 /**
Chris@16 643 * checks if vertex v has a connect to the source-vertex (@var m_source)
Chris@16 644 * @param v the vertex which is checked
Chris@16 645 * @return true if a path to the source was found, false if not
Chris@16 646 */
Chris@16 647 inline bool has_source_connect(vertex_descriptor v){
Chris@16 648 tDistanceVal current_distance = 0;
Chris@16 649 vertex_descriptor current_vertex = v;
Chris@16 650 while(true){
Chris@16 651 if(get(m_time_map, current_vertex) == m_time){
Chris@16 652 //we found a node which was already checked this round. use it for distance calculations
Chris@16 653 current_distance += get(m_dist_map, current_vertex);
Chris@16 654 break;
Chris@16 655 }
Chris@16 656 if(current_vertex == m_source){
Chris@16 657 put(m_time_map, m_source, m_time);
Chris@16 658 break;
Chris@16 659 }
Chris@16 660 if(has_parent(current_vertex)){
Chris@16 661 //it has a parent, so get it
Chris@16 662 current_vertex = source(get_edge_to_parent(current_vertex), m_g);
Chris@16 663 ++current_distance;
Chris@16 664 } else{
Chris@16 665 //no path found
Chris@16 666 return false;
Chris@16 667 }
Chris@16 668 }
Chris@16 669 current_vertex=v;
Chris@16 670 while(get(m_time_map, current_vertex) != m_time){
Chris@16 671 put(m_dist_map, current_vertex, current_distance);
Chris@16 672 --current_distance;
Chris@16 673 put(m_time_map, current_vertex, m_time);
Chris@16 674 current_vertex = source(get_edge_to_parent(current_vertex), m_g);
Chris@16 675 }
Chris@16 676 return true;
Chris@16 677 }
Chris@16 678
Chris@16 679 /**
Chris@16 680 * returns true, if p is closer to a terminal than q
Chris@16 681 */
Chris@16 682 inline bool is_closer_to_terminal(vertex_descriptor p, vertex_descriptor q){
Chris@16 683 //checks the timestamps first, to build no cycles, and after that the real distance
Chris@16 684 return (get(m_time_map, q) <= get(m_time_map, p) &&
Chris@16 685 get(m_dist_map, q) > get(m_dist_map, p)+1);
Chris@16 686 }
Chris@16 687
Chris@16 688 ////////
Chris@16 689 // member vars
Chris@16 690 ////////
Chris@16 691 Graph& m_g;
Chris@16 692 IndexMap m_index_map;
Chris@16 693 EdgeCapacityMap m_cap_map;
Chris@16 694 ResidualCapacityEdgeMap m_res_cap_map;
Chris@16 695 ReverseEdgeMap m_rev_edge_map;
Chris@16 696 PredecessorMap m_pre_map; //stores paths found in the growth stage
Chris@16 697 ColorMap m_tree_map; //maps each vertex into one of the two search tree or none (gray())
Chris@16 698 DistanceMap m_dist_map; //stores distance to source/sink nodes
Chris@16 699 vertex_descriptor m_source;
Chris@16 700 vertex_descriptor m_sink;
Chris@16 701
Chris@16 702 tQueue m_active_nodes;
Chris@16 703 std::vector<bool> m_in_active_list_vec;
Chris@16 704 iterator_property_map<std::vector<bool>::iterator, IndexMap> m_in_active_list_map;
Chris@16 705
Chris@16 706 std::list<vertex_descriptor> m_orphans;
Chris@16 707 tQueue m_child_orphans; // we use a second queuqe for child orphans, as they are FIFO processed
Chris@16 708
Chris@16 709 std::vector<bool> m_has_parent_vec;
Chris@16 710 iterator_property_map<std::vector<bool>::iterator, IndexMap> m_has_parent_map;
Chris@16 711
Chris@16 712 std::vector<long> m_time_vec; //timestamp of each node, used for sink/source-path calculations
Chris@16 713 iterator_property_map<std::vector<long>::iterator, IndexMap> m_time_map;
Chris@16 714 tEdgeVal m_flow;
Chris@16 715 long m_time;
Chris@16 716 vertex_descriptor m_last_grow_vertex;
Chris@16 717 out_edge_iterator m_last_grow_edge_it;
Chris@16 718 out_edge_iterator m_last_grow_edge_end;
Chris@16 719 };
Chris@16 720
Chris@16 721 } //namespace boost::detail
Chris@16 722
Chris@16 723 /**
Chris@16 724 * non-named-parameter version, given everything
Chris@16 725 * this is the catch all version
Chris@16 726 */
Chris@16 727 template<class Graph,
Chris@16 728 class CapacityEdgeMap,
Chris@16 729 class ResidualCapacityEdgeMap,
Chris@16 730 class ReverseEdgeMap, class PredecessorMap,
Chris@16 731 class ColorMap,
Chris@16 732 class DistanceMap,
Chris@16 733 class IndexMap>
Chris@16 734 typename property_traits<CapacityEdgeMap>::value_type
Chris@16 735 boykov_kolmogorov_max_flow(Graph& g,
Chris@16 736 CapacityEdgeMap cap,
Chris@16 737 ResidualCapacityEdgeMap res_cap,
Chris@16 738 ReverseEdgeMap rev_map,
Chris@16 739 PredecessorMap pre_map,
Chris@16 740 ColorMap color,
Chris@16 741 DistanceMap dist,
Chris@16 742 IndexMap idx,
Chris@16 743 typename graph_traits<Graph>::vertex_descriptor src,
Chris@16 744 typename graph_traits<Graph>::vertex_descriptor sink)
Chris@16 745 {
Chris@16 746 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 747 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
Chris@16 748
Chris@16 749 //as this method is the last one before we instantiate the solver, we do the concept checks here
Chris@16 750 BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> )); //to have vertices(), num_vertices(),
Chris@16 751 BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<Graph> )); //to have edges()
Chris@16 752 BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> )); //to have source(), target() and out_edges()
Chris@16 753 BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<CapacityEdgeMap, edge_descriptor> )); //read flow-values from edges
Chris@16 754 BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ResidualCapacityEdgeMap, edge_descriptor> )); //write flow-values to residuals
Chris@16 755 BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<ReverseEdgeMap, edge_descriptor> )); //read out reverse edges
Chris@16 756 BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<PredecessorMap, vertex_descriptor> )); //store predecessor there
Chris@16 757 BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, vertex_descriptor> )); //write corresponding tree
Chris@16 758 BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<DistanceMap, vertex_descriptor> )); //write distance to source/sink
Chris@16 759 BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<IndexMap, vertex_descriptor> )); //get index 0...|V|-1
Chris@16 760 BOOST_ASSERT(num_vertices(g) >= 2 && src != sink);
Chris@16 761
Chris@16 762 detail::bk_max_flow<
Chris@16 763 Graph, CapacityEdgeMap, ResidualCapacityEdgeMap, ReverseEdgeMap,
Chris@16 764 PredecessorMap, ColorMap, DistanceMap, IndexMap
Chris@16 765 > algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink);
Chris@16 766
Chris@16 767 return algo.max_flow();
Chris@16 768 }
Chris@16 769
Chris@16 770 /**
Chris@16 771 * non-named-parameter version, given capacity, residucal_capacity,
Chris@16 772 * reverse_edges, and an index map.
Chris@16 773 */
Chris@16 774 template<class Graph,
Chris@16 775 class CapacityEdgeMap,
Chris@16 776 class ResidualCapacityEdgeMap,
Chris@16 777 class ReverseEdgeMap,
Chris@16 778 class IndexMap>
Chris@16 779 typename property_traits<CapacityEdgeMap>::value_type
Chris@16 780 boykov_kolmogorov_max_flow(Graph& g,
Chris@16 781 CapacityEdgeMap cap,
Chris@16 782 ResidualCapacityEdgeMap res_cap,
Chris@16 783 ReverseEdgeMap rev,
Chris@16 784 IndexMap idx,
Chris@16 785 typename graph_traits<Graph>::vertex_descriptor src,
Chris@16 786 typename graph_traits<Graph>::vertex_descriptor sink)
Chris@16 787 {
Chris@16 788 typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
Chris@16 789 std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
Chris@16 790 std::vector<default_color_type> color_vec(n_verts);
Chris@16 791 std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
Chris@16 792 return
Chris@16 793 boykov_kolmogorov_max_flow(
Chris@16 794 g, cap, res_cap, rev,
Chris@16 795 make_iterator_property_map(predecessor_vec.begin(), idx),
Chris@16 796 make_iterator_property_map(color_vec.begin(), idx),
Chris@16 797 make_iterator_property_map(distance_vec.begin(), idx),
Chris@16 798 idx, src, sink);
Chris@16 799 }
Chris@16 800
Chris@16 801 /**
Chris@16 802 * non-named-parameter version, some given: capacity, residual_capacity,
Chris@16 803 * reverse_edges, color_map and an index map. Use this if you are interested in
Chris@16 804 * the minimum cut, as the color map provides that info.
Chris@16 805 */
Chris@16 806 template<class Graph,
Chris@16 807 class CapacityEdgeMap,
Chris@16 808 class ResidualCapacityEdgeMap,
Chris@16 809 class ReverseEdgeMap,
Chris@16 810 class ColorMap,
Chris@16 811 class IndexMap>
Chris@16 812 typename property_traits<CapacityEdgeMap>::value_type
Chris@16 813 boykov_kolmogorov_max_flow(Graph& g,
Chris@16 814 CapacityEdgeMap cap,
Chris@16 815 ResidualCapacityEdgeMap res_cap,
Chris@16 816 ReverseEdgeMap rev,
Chris@16 817 ColorMap color,
Chris@16 818 IndexMap idx,
Chris@16 819 typename graph_traits<Graph>::vertex_descriptor src,
Chris@16 820 typename graph_traits<Graph>::vertex_descriptor sink)
Chris@16 821 {
Chris@16 822 typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
Chris@16 823 std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
Chris@16 824 std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
Chris@16 825 return
Chris@16 826 boykov_kolmogorov_max_flow(
Chris@16 827 g, cap, res_cap, rev,
Chris@16 828 make_iterator_property_map(predecessor_vec.begin(), idx),
Chris@16 829 color,
Chris@16 830 make_iterator_property_map(distance_vec.begin(), idx),
Chris@16 831 idx, src, sink);
Chris@16 832 }
Chris@16 833
Chris@16 834 /**
Chris@16 835 * named-parameter version, some given
Chris@16 836 */
Chris@16 837 template<class Graph, class P, class T, class R>
Chris@16 838 typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
Chris@16 839 boykov_kolmogorov_max_flow(Graph& g,
Chris@16 840 typename graph_traits<Graph>::vertex_descriptor src,
Chris@16 841 typename graph_traits<Graph>::vertex_descriptor sink,
Chris@16 842 const bgl_named_params<P, T, R>& params)
Chris@16 843 {
Chris@16 844 return
Chris@16 845 boykov_kolmogorov_max_flow(
Chris@16 846 g,
Chris@16 847 choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
Chris@16 848 choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity),
Chris@16 849 choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
Chris@16 850 choose_pmap(get_param(params, vertex_predecessor), g, vertex_predecessor),
Chris@16 851 choose_pmap(get_param(params, vertex_color), g, vertex_color),
Chris@16 852 choose_pmap(get_param(params, vertex_distance), g, vertex_distance),
Chris@16 853 choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
Chris@16 854 src, sink);
Chris@16 855 }
Chris@16 856
Chris@16 857 /**
Chris@16 858 * named-parameter version, none given
Chris@16 859 */
Chris@16 860 template<class Graph>
Chris@16 861 typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
Chris@16 862 boykov_kolmogorov_max_flow(Graph& g,
Chris@16 863 typename graph_traits<Graph>::vertex_descriptor src,
Chris@16 864 typename graph_traits<Graph>::vertex_descriptor sink)
Chris@16 865 {
Chris@16 866 bgl_named_params<int, buffer_param_t> params(0); // bogus empty param
Chris@16 867 return boykov_kolmogorov_max_flow(g, src, sink, params);
Chris@16 868 }
Chris@16 869
Chris@16 870 } // namespace boost
Chris@16 871
Chris@16 872 #endif // BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
Chris@16 873