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
|