mirror of
https://github.com/boostorg/graph.git
synced 2025-05-09 23:14:00 +00:00
Integrate Kolmogorov's max flow algorithm, from Stephan Diederich.
[SVN r36125]
This commit is contained in:
parent
a86397fc34
commit
1cfa23497b
@ -405,6 +405,15 @@ Morgan Kaufmann Publishers, San Fransisco, 1997.
|
||||
<em>Modern Compiler Implementation in JAVA</em><br>
|
||||
Cambridge University Press, 1998.
|
||||
|
||||
<p></p><dt><a name="kolmogorov03">68</a>
|
||||
<dd>Vladimir Kolmogorov<br>
|
||||
<em>Graph Based Algorithms for Scene Reconstruction from Two or More Views</em><br>
|
||||
PhD thesis, Cornell University, September 2003.
|
||||
|
||||
<p></p><dt><a name="boykov-kolmogorov04">69</a>
|
||||
<dd>Yuri Boykov and Vladimir Kolmogorov<br>
|
||||
<em><a href="http://www.csd.uwo.ca/faculty/yuri/Abstracts/pami04-abs.html">An Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy Minimization in Vision</a></em><br>
|
||||
In IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 26, no. 9, pp. 1124-1137, Sept. 2004.
|
||||
</dl>
|
||||
|
||||
<br>
|
||||
|
@ -79,6 +79,8 @@ This algorithm provides a very simple and easy to implement solution to
|
||||
the maximum flow problem. However, there are several reasons why this
|
||||
algorithm is not as good as the <a
|
||||
href="./push_relabel_max_flow.html"><tt>push_relabel_max_flow()</tt></a>
|
||||
or the <a
|
||||
href="./kolmogorov_max_flow.html"><tt>kolmogorov_max_flow()</tt></a>
|
||||
algorithm.
|
||||
|
||||
<ul>
|
||||
@ -218,7 +220,8 @@ from a file in the DIMACS format and computes the maximum flow.
|
||||
|
||||
<h3>See Also</h3>
|
||||
|
||||
<a href="./push_relabel_max_flow.html"><tt>push_relabel_max_flow()</tt></a>.
|
||||
<a href="./push_relabel_max_flow.html"><tt>push_relabel_max_flow()</tt></a><br>
|
||||
<a href="./kolmogorov_max_flow.html"><tt>kolmogorov_max_flow()</tt></a>.
|
||||
|
||||
<br>
|
||||
<HR>
|
||||
|
BIN
doc/figs/kolmogorov_max_flow.gif
Normal file
BIN
doc/figs/kolmogorov_max_flow.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
@ -80,6 +80,12 @@ September 27, 2000.
|
||||
<h2>Changes by version</h2>
|
||||
<a name="by-version">
|
||||
<ul>
|
||||
<a name="1.35.0"></a><li>Version 1.35.0<br><b>New algorithms and components</b>
|
||||
<ul>
|
||||
<li><a href="kolmogorov_max_flow.html"><tt>kolmogorov_max_flow</tt></a>, from Stephan Diederich as part of the <a href="http://code.google.com/soc/">2006 Google Summer of Code</a>.</li>
|
||||
<li><a href="read_dimacs.html">read_dimacs</a> and <a href="write_dimacs.html">write_dimacs</a> for max-flow problems, from Stephan Diederich.</li>
|
||||
</ul>
|
||||
</li><br>
|
||||
<a name="1.34.0"></a><li>Version 1.34.0<br><b>New algorithms and components</b>
|
||||
<ul>
|
||||
<li><a href="maximum_matching.html"><tt>edmonds_maximum_cardinality_matching</tt></a>, from Aaron Windsor.</li>
|
||||
|
384
doc/kolmogorov_max_flow.html
Normal file
384
doc/kolmogorov_max_flow.html
Normal file
@ -0,0 +1,384 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-15">
|
||||
<TITLE>Boost Graph Library: Kolmogorov Maximum Flow</TITLE>
|
||||
<META NAME="GENERATOR" CONTENT="OpenOffice.org 2.0 (Linux)">
|
||||
<META NAME="CREATED" CONTENT="20060820;17315200">
|
||||
<META NAME="CHANGEDBY" CONTENT="Stephan Diederich">
|
||||
<META NAME="CHANGED" CONTENT="20060820;23125100">
|
||||
<!--
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This documentation may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
<STYLE>
|
||||
<!--
|
||||
TD P { color: #000000 }
|
||||
H1 { color: #000000 }
|
||||
P { color: #000000 }
|
||||
PRE { color: #000000 }
|
||||
H3 { color: #000000 }
|
||||
BLOCKQUOTE { color: #000000 }
|
||||
A:link { color: #0000ee }
|
||||
A:visited { color: #551a8b }
|
||||
-->
|
||||
</STYLE>
|
||||
</HEAD>
|
||||
<BODY LANG="de-DE" TEXT="#000000" LINK="#0000ee" VLINK="#551a8b" BGCOLOR="#ffffff" DIR="LTR">
|
||||
<P><IMG SRC="../../../boost.png" NAME="Grafik1" ALT="C++ Boost" ALIGN=BOTTOM WIDTH=277 HEIGHT=86 BORDER=0>
|
||||
</P>
|
||||
<H1><A NAME="sec:kolmogorov_max_flow"></A><TT>kolmogorov_max_flow</TT>
|
||||
</H1>
|
||||
<PRE><I>// named parameter version</I>
|
||||
template <class Graph, class P, class T, class R>
|
||||
typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
|
||||
kolmogorov_max_flow(Graph& g,
|
||||
typename graph_traits<Graph>::vertex_descriptor src,
|
||||
typename graph_traits<Graph>::vertex_descriptor sink,
|
||||
const bgl_named_params<P, T, R>& params = <I>all defaults</I>)
|
||||
|
||||
<I>// non-named parameter version</I>
|
||||
template <class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap,
|
||||
class PredecessorMap, class ColorMap, class DistanceMap, class IndexMap>
|
||||
typename property_traits<CapacityEdgeMap>::value_type
|
||||
kolmogorov_max_flow(Graph& g,
|
||||
CapacityEdgeMap cap,
|
||||
ResidualCapacityEdgeMap res_cap,
|
||||
ReverseEdgeMap rev_map,
|
||||
PredecessorMap pre_map,
|
||||
ColorMap color,
|
||||
DistanceMap dist,
|
||||
IndexMap idx,
|
||||
typename graph_traits <Graph>::vertex_descriptor src,
|
||||
typename graph_traits <Graph >::vertex_descriptor sink)</PRE><P>
|
||||
<FONT SIZE=3>Additional overloaded versions for non-named parameters
|
||||
are provided (without DistanceMap/ColorMap/DistanceMap; for those
|
||||
iterator_property_maps with the provided index map are used)</FONT></P>
|
||||
<P>The <TT>kolmogorov_max_flow()</TT> function calculates the maximum
|
||||
flow of a network. See Section <A HREF="graph_theory_review.html#sec:network-flow-algorithms">Network
|
||||
Flow Algorithms</A> for a description of maximum flow. The calculated
|
||||
maximum flow will be the return value of the function. The function
|
||||
also calculates the flow values <I>f(u,v)</I> for all <I>(u,v)</I> in
|
||||
<I>E</I>, which are returned in the form of the residual capacity
|
||||
<I>r(u,v) = c(u,v) - f(u,v)</I>.
|
||||
</P>
|
||||
<P><B>Requirements:</B><BR>The directed graph <I>G=(V,E)</I> that
|
||||
represents the network must include a reverse edge for every edge in
|
||||
<I>E</I>. That is, the input graph should be <I>G<SUB>in</SUB> =
|
||||
(V,{E U E<SUP>T</SUP>})</I>. The <TT>ReverseEdgeMap</TT> argument <TT>rev</TT>
|
||||
must map each edge in the original graph to its reverse edge, that is
|
||||
<I>(u,v) -> (v,u)</I> for all <I>(u,v)</I> in <I>E</I>.
|
||||
</P>
|
||||
<P>Remarks: While the push-relabel method states that each edge in <I>E<SUP>T</SUP></I>
|
||||
has to have capacity of 0, the reverse edges for this algorithm ARE
|
||||
allowed to carry capacities. If there are already reverse edges in
|
||||
the input Graph <I><FONT FACE="Courier New, monospace">G</FONT></I>,
|
||||
those can be used. This can halve the amount of edges and will
|
||||
noticeably increase the performance.<BR><BR><B>Algorithm
|
||||
description:</B><BR>Kolmogorov's algorithm is a variety of the
|
||||
augmenting-path algorithm. Standard augmenting path algorithms find
|
||||
shortest paths from source to sink vertex and augment them by
|
||||
substracting the bottleneck capacity found on that path from the
|
||||
residual capacities of each edge and adding it to the total flow.
|
||||
Additionally the minimum capacity is added to the residual capacity
|
||||
of the reverse edges. If no more paths in the residual-edge tree are
|
||||
found, the algorithm terminates. Instead of finding a new shortest
|
||||
path from source to sink in the graph in each iteration, Kolmogorov's
|
||||
version keeps the already found paths as follows:</P>
|
||||
<P>The algorithm builds up two search trees, a source-tree and a
|
||||
sink-tree. Each vertex has a label (stored in <I>ColorMap</I>) to
|
||||
which tree it belongs and a status-flag if this vertex is active or
|
||||
passive. In the beginning of the algorithm only the source and the
|
||||
sink are colored (source==white, sink==black) and have active status.
|
||||
All other vertices are colored gray. The algorithm consists of three
|
||||
phases:</P>
|
||||
<P><I>grow-phase</I>: In this phase active vertices are allowed to
|
||||
acquire neighbor vertices that are connected through an edge that has
|
||||
a capacity-value greater than zero. Acquiring means that those vertices
|
||||
become active and belong now to the search tree of the current
|
||||
active vertex. If there are no more valid connections to neighbor
|
||||
vertices, the current vertex becomes passive and the grow phase
|
||||
continues with the next active vertex. The grow phase terminates if
|
||||
there are no more active vertices left or a vertex discovers a vertex
|
||||
from the other search tree through an unsaturated edge. In this case
|
||||
a path from source to sink is found.</P>
|
||||
<P><I>augment-phase</I>: This phase augments the path that was found
|
||||
in the grow phase. First it finds the bottleneck capacity of the
|
||||
found path, and then it updates the residual-capacity of the edges
|
||||
from this path by substracting the bottleneck capacity from the
|
||||
residual capacity. Furthermore the residual capacity of the reverse
|
||||
edges are updated by adding the bottleneck capacity. This phase can
|
||||
destroy the built up search trees, as it creates at least one
|
||||
saturated edge. That means, that the search trees collapse to
|
||||
forests, because a condition for the search trees is, that each
|
||||
vertex in them has a valid (=non-saturated) connection to a terminal.</P>
|
||||
<P><I>adoption-phase</I>: Here the search trees are reconstructed. A
|
||||
simple solution would be to mark all vertices coming after the first
|
||||
orphan in the found path free vertices (gray). A more sophisticated
|
||||
solution is to give those orphans new parents: The neighbor vertices
|
||||
are checked if they have a valid connection to the same terminal like
|
||||
this vertex had (a path with unsaturated edges). If there is one,
|
||||
this vertex becomes the new parent of the current orphan and this
|
||||
forest is re-included into the search tree. If no new valid parent is
|
||||
found, this vertex becomes a free vertex (marked gray), and it's
|
||||
children become orphans. The adoption phase terminates if there are
|
||||
no more orphans.</P>
|
||||
<P><IMG SRC="figs/kolmogorov_max_flow.gif" NAME="Grafik2" ALIGN=LEFT WIDTH=827 HEIGHT=311 BORDER=0><BR CLEAR=LEFT><B>Details:</B></P>
|
||||
<UL>
|
||||
<LI><P>Marking heuristics: A timestamp is stored for each vertex
|
||||
which shows in which iteration of the algorithm the distance to the
|
||||
corresponding terminal was calculated.
|
||||
</P>
|
||||
<UL>
|
||||
<LI><P>This distance is used and gets calculated in the
|
||||
adoption-phase. In order to find a valid new parent for an orphan,
|
||||
the possible parent is checked for a connection to the terminal to
|
||||
which tree it belongs. If there is such a connection, the path is
|
||||
tagged with the current time-stamp, and the distance value. If
|
||||
another orphan has to find a parent and it comes across a vertex
|
||||
with a current timestamp, this information is used.</P>
|
||||
<LI><P>The distance is also used in the grow-phase. If a vertex
|
||||
comes across another vertex of the same tree while searching for
|
||||
new vertices, the other's distance is compared to its distance. If
|
||||
it is smaller, that other vertex becomes the new parent of the
|
||||
current. This can decrease the length of the search paths, and so
|
||||
amount of adoptions.</P>
|
||||
</UL>
|
||||
<LI><P>Ordering of orphans: As described above, the augment-phase
|
||||
and the adoption phase can create orphans. The orphans the
|
||||
augment-phase generates, are ordered according to their distance to
|
||||
the terminals (smallest first). This combined with the
|
||||
distance/timestamp heuristics results in the possibility for not
|
||||
having to recheck terminal-connections too often. New orphans which
|
||||
are generated in adoption phase are processed before orphans from
|
||||
the main queue for the same reason.</P>
|
||||
</UL>
|
||||
<P><BR><B>Implementation notes:</B></P>
|
||||
<P>The algorithm is mainly implemented as described in the PhD thesis
|
||||
of Kolmogorov. Few changes were made for increasing performance:</P>
|
||||
<UL>
|
||||
<LI><P>initialization: the algorithm first augments all paths from
|
||||
source->sink and all paths from source->VERTEX->sink. This
|
||||
improves especially graph-cuts used in image vision where nearly
|
||||
each vertex has a source and sink connect. During this step, all
|
||||
vertices that have an unsaturated connection from source are added
|
||||
to the active vertex list and so the source is not.
|
||||
</P>
|
||||
<LI><P>active vertices: Kolmogorov uses two lists for active nodes
|
||||
and states that new active vertices are added to the rear of the
|
||||
second. Fetching an active vertex is done from the beginning of the
|
||||
first list. If the first list is empty, it is exchanged by the
|
||||
second. This implementation uses just one list.</P>
|
||||
<LI><P>grow-phase: In the grow phase the first vertex in the
|
||||
active-list is taken and all outgoing edges are checked if they are
|
||||
unsaturated. This decreases performance for graphs with high-edge
|
||||
density. This implementation stores the last accessed edge and
|
||||
continues with it, if the first vertex in the active-list is the
|
||||
same one as during the last grow-phase.</P>
|
||||
</UL>
|
||||
<P>This algorithm [<A HREF="bibliography.html#kolmogorov03">68</a>, <a href="bibliography.html#boykov-kolmogorov04">69</a>] was developed by Boykov and Kolmogorov.
|
||||
</P>
|
||||
<H3>Where Defined</H3>
|
||||
<P><TT><A HREF="../../../boost/graph/kolmogorov_max_flow.hpp">boost/graph/kolmogorov_max_flow.hpp</A></TT>
|
||||
</P>
|
||||
<H3>Parameters</H3>
|
||||
<P>IN: <TT>Graph& g</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>A directed graph. The graph's type must be a model of
|
||||
<A HREF="VertexListGraph.html">Vertex List Graph</A>, <A HREF="EdgeListGraph.html">Edge
|
||||
List Graph</A> and <A HREF="IncidenceGraph.html">Incidence Graph</A>.
|
||||
For each edge <I>(u,v)</I> in the graph, the reverse edge <I>(v,u)</I>
|
||||
must also be in the graph.
|
||||
</BLOCKQUOTE>
|
||||
<P>IN: <TT>vertex_descriptor src</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>The source vertex for the flow network graph.
|
||||
</BLOCKQUOTE>
|
||||
<P>IN: <TT>vertex_descriptor sink</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>The sink vertex for the flow network graph.
|
||||
</BLOCKQUOTE>
|
||||
<H3>Named Parameters</H3>
|
||||
<P>IN: <TT>capacity_map(EdgeCapacityMap cap)</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>The edge capacity property map. The type must be a model
|
||||
of a constant <A HREF="../../property_map/LvaluePropertyMap.html">Lvalue
|
||||
Property Map</A>. The key type of the map must be the graph's edge
|
||||
descriptor type.<BR><B>Default:</B> <TT>get(edge_capacity, g)</TT>
|
||||
</BLOCKQUOTE>
|
||||
<P>OUT: <TT>residual_capacity_map(ResidualCapacityEdgeMap res)</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>The edge residual capacity property map. The type must be
|
||||
a model of a mutable <A HREF="../../property_map/LvaluePropertyMap.html">Lvalue
|
||||
Property Map</A>. The key type of the map must be the graph's edge
|
||||
descriptor type.<BR><B>Default:</B> <TT>get(edge_residual_capacity,
|
||||
g)</TT>
|
||||
</BLOCKQUOTE>
|
||||
<P>IN: <TT>reverse_edge_map(ReverseEdgeMap rev)</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>An edge property map that maps every edge <I>(u,v)</I> in
|
||||
the graph to the reverse edge <I>(v,u)</I>. The map must be a model
|
||||
of constant <A HREF="../../property_map/LvaluePropertyMap.html">Lvalue
|
||||
Property Map</A>. The key type of the map must be the graph's edge
|
||||
descriptor type.<BR><B>Default:</B> <TT>get(edge_reverse, g)</TT>
|
||||
</BLOCKQUOTE>
|
||||
<P>UTIL: <TT>vertex_predecessor(PredecessorMap pre_map)</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>A vertex property map that stores the edge to the vertex'
|
||||
predecessor. The map must be a model of mutable <A HREF="../../property_map/LvaluePropertyMap.html">Lvalue
|
||||
Property Map</A>. The key type of the map must be the graph's vertex
|
||||
descriptor type.<BR><B>Default:</B> <TT>get(vertex_predecessor, g)</TT>
|
||||
</BLOCKQUOTE>
|
||||
<P>OUT/UTIL: <TT>vertex_color(ColorMap color)</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>A vertex property map that stores a color for edge
|
||||
vertex. If the color of a vertex after running the algorithm is white
|
||||
the vertex belongs to the source tree else it belongs to the
|
||||
sink-tree (used for minimum cuts). The map must be a model of mutable
|
||||
<A HREF="../../property_map/LvaluePropertyMap.html">Lvalue Property
|
||||
Map</A>. The key type of the map must be the graph's vertex
|
||||
descriptor type.<BR><B>Default:</B> <TT>get(vertex_color, g)</TT>
|
||||
</BLOCKQUOTE>
|
||||
<P>UTIL: <TT>vertex_distance(DistanceMap dist)</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>A vertex property map that stores the distance to the
|
||||
corresponding terminal. It's a utility-map for speeding up the
|
||||
algorithm. The map must be a model of mutable <A HREF="../../property_map/LvaluePropertyMap.html">Lvalue
|
||||
Property Map</A>. The key type of the map must be the graph's vertex
|
||||
descriptor type.<BR><B>Default:</B> <TT>get(vertex_distance, g)</TT>
|
||||
</BLOCKQUOTE>
|
||||
<P>IN: <TT>vertex_index_map(VertexIndexMap index_map)</TT>
|
||||
</P>
|
||||
<BLOCKQUOTE>Maps each vertex of the graph to a unique integer in the
|
||||
range <TT>[0, num_vertices(g))</TT>. The map must be a model of
|
||||
constant <A HREF="../../property_map/LvaluePropertyMap.html">LvaluePropertyMap</A>.
|
||||
The key type of the map must be the graph's vertex descriptor
|
||||
type.<BR><B>Default:</B> <TT>get(vertex_index, g)</TT>
|
||||
</BLOCKQUOTE>
|
||||
<H3>Example</H3>
|
||||
<P>This reads an example maximum flow problem (a graph with edge
|
||||
capacities) from a file in the DIMACS format (<TT><A HREF="../example/max_flow.dat">example/max_flow.dat</A></TT>).
|
||||
The source for this example can be found in
|
||||
<TT><A HREF="../example/kolmogorov-eg.cpp">example/kolmogorov-eg.cpp</A></TT>.
|
||||
</P>
|
||||
<PRE>#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/graph/kolmogorov_map_flow.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/read_dimacs.hpp>
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
typedef adjacency_list_traits<vecS, vecS, directedS> Traits;
|
||||
typedef adjacency_list<vecS, vecS, directedS,
|
||||
property<vertex_name_t, std::string>,
|
||||
property<edge_capacity_t, long,
|
||||
property<edge_residual_capacity_t, long,
|
||||
property<edge_reverse_t, Traits::edge_descriptor> > >
|
||||
> Graph;
|
||||
|
||||
Graph g;
|
||||
long flow;
|
||||
|
||||
property_map<Graph, edge_capacity_t>::type
|
||||
capacity = get(edge_capacity, g);
|
||||
property_map<Graph, edge_reverse_t>::type
|
||||
rev = get(edge_reverse, g);
|
||||
property_map<Graph, edge_residual_capacity_t>::type
|
||||
residual_capacity = get(edge_residual_capacity, g);
|
||||
|
||||
Traits::vertex_descriptor s, t;
|
||||
read_dimacs_max_flow(g, capacity, rev, s, t);
|
||||
|
||||
flow = kolmogorov_max_flow(g, s, t);
|
||||
|
||||
std::cout << "c The total flow:" << std::endl;
|
||||
std::cout << "s " << flow << std::endl << std::endl;
|
||||
|
||||
std::cout << "c flow values:" << std::endl;
|
||||
graph_traits<Graph>::vertex_iterator u_iter, u_end;
|
||||
graph_traits<Graph>::out_edge_iterator ei, e_end;
|
||||
for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
|
||||
for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
|
||||
if (capacity[*ei] > 0)
|
||||
std::cout << "f " << *u_iter << " " << target(*ei, g) << " "
|
||||
<< (capacity[*ei] - residual_capacity[*ei]) << std::endl;
|
||||
return 0;
|
||||
}</PRE><P>
|
||||
The output is:
|
||||
</P>
|
||||
<PRE>c The total flow:
|
||||
s 13
|
||||
|
||||
c flow values:
|
||||
f 0 6 3
|
||||
f 0 1 0
|
||||
f 0 2 10
|
||||
f 1 5 1
|
||||
f 1 0 0
|
||||
f 1 3 0
|
||||
f 2 4 4
|
||||
f 2 3 6
|
||||
f 2 0 0
|
||||
f 3 7 5
|
||||
f 3 2 0
|
||||
f 3 1 1
|
||||
f 4 5 4
|
||||
f 4 6 0
|
||||
f 5 4 0
|
||||
f 5 7 5
|
||||
f 6 7 3
|
||||
f 6 4 0
|
||||
f 7 6 0
|
||||
f 7 5 0</PRE><H3>
|
||||
See Also</H3>
|
||||
<P STYLE="margin-bottom: 0cm"><TT><A HREF="edmunds_karp_max_flow.html">edmunds_karp_max_flow()</A></TT>,<BR><TT><A HREF="push_relabel_max_flow.html">push_relabel_max_flow()</A></TT>.
|
||||
</P>
|
||||
<HR>
|
||||
<TABLE CELLPADDING=2 CELLSPACING=2>
|
||||
<TR VALIGN=TOP>
|
||||
<TD>
|
||||
<P>Copyright © 2006</P>
|
||||
</TD>
|
||||
<TD>
|
||||
<P>Stephan Diederich, University
|
||||
Mannheim(<A HREF="mailto:diederich@ti.uni-manheim.de">diederich@ti.uni-manheim.de</A>)</P>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<P><BR><BR>
|
||||
</P>
|
||||
</BODY>
|
||||
</HTML>
|
@ -229,7 +229,8 @@ f 6 7 1
|
||||
|
||||
<h3>See Also</h3>
|
||||
|
||||
<a href="./edmunds_karp_max_flow.html"><tt>edmunds_karp_max_flow()</tt></a>.
|
||||
<a href="./edmunds_karp_max_flow.html"><tt>edmunds_karp_max_flow()</tt></a><br>
|
||||
<a href="./kolmogorov_max_flow.html"><tt>kolmogorov_max_flow()</tt></a>.
|
||||
|
||||
<br>
|
||||
<HR>
|
||||
|
99
doc/read_dimacs.html
Normal file
99
doc/read_dimacs.html
Normal file
@ -0,0 +1,99 @@
|
||||
<HTML>
|
||||
<!--
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
<Head>
|
||||
<Title>Boost Graph Library: read_dimacs_max_flow</Title>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||
ALINK="#ff0000">
|
||||
<IMG SRC="../../../boost.png"
|
||||
ALT="C++ Boost" width="277" height="86">
|
||||
<BR Clear>
|
||||
|
||||
<H1><A NAME="sec:read_dimacs_max_flow">
|
||||
<TT>read_dimacs_max_flow</TT>
|
||||
</H1>
|
||||
|
||||
|
||||
<pre>
|
||||
//reads a graph with attached edge_capacity properties from an std::istream
|
||||
template <class Graph, class CapacityMap, class ReverseEdgeMap>
|
||||
int read_dimacs_max_flow(Graph& g,
|
||||
CapacityMap capacity,
|
||||
ReverseEdgeMap reverse_edge,
|
||||
typename graph_traits<Graph>::vertex_descriptor& src,
|
||||
typename graph_traits<Graph>::vertex_descriptor& sink,
|
||||
std::istream& in=std::cin)
|
||||
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This method reads a BGL graph object from a max-flow problem description in extended dimacs format. (see <a href="http://www.avglab.com/andrew/CATS/maxflow_formats.htm"><TT>Goldbergs site</TT></a> for more information). For each edge found in the
|
||||
file an additional reverse_edge is added and set in the reverse_edge map. Source- and sink-vertex-descriptors are set according to the dimacs file.
|
||||
|
||||
<H3>Where Defined</H3>
|
||||
|
||||
<P>
|
||||
<a href="../../../boost/graph/read_dimacs.hpp"><TT>boost/graph/read_dimacs.hpp</TT></a>
|
||||
|
||||
<h3>Parameters</h3>
|
||||
IN: <tt>Graph& g</tt>
|
||||
<blockquote>
|
||||
A directed or undirected graph. The graph's type must be a model of <a href="./IncidenceGraph.html">IncidenceGraph</a>.
|
||||
</blockquote>
|
||||
|
||||
OUT: <tt>CapacityMap capacity</tt>
|
||||
<blockquote>
|
||||
A property map that models <a href="../../property_map/LvaluePropertyMap.html">mutable Lvalue Property Map</a> whose key type is the edge descriptor of the graph. <br>
|
||||
</blockquote>
|
||||
|
||||
OUT: <tt>ReverseEdgeMap reverse_edge</tt>
|
||||
<blockquote>
|
||||
A property map that models <a href="../../property_map/LvaluePropertyMap.html">mutable Lvalue Property Map</a> whose key and value type is the edge descriptor of the graph. This map stores the corresponding reverse edge for each each in Graph g.<br>
|
||||
</blockquote>
|
||||
|
||||
IN: <tt>std::istream& in</tt>
|
||||
<blockquote>
|
||||
A standard <tt>std::istream</tt> object. <br>
|
||||
<b>Default</b>: <tt>std::cin (for backward compatibility)</tt>
|
||||
</blockquote>
|
||||
|
||||
<H3>
|
||||
Example
|
||||
</H3>
|
||||
A short <a href="../example/read_write_dimacs-eg.cpp">example</a> which uses read_dimacs and write_dimacs is located in the examples directory.
|
||||
|
||||
<h3>See Also</h3>
|
||||
|
||||
<a href="./write_dimacs.html"><tt>write_dimacs</tt></a>
|
||||
</BODY>
|
||||
</HTML>
|
@ -174,6 +174,7 @@
|
||||
<OL>
|
||||
<LI><A href="./edmunds_karp_max_flow.html"><tt>edmunds_karp_max_flow</tt></A>
|
||||
<LI><A href="./push_relabel_max_flow.html"><tt>push_relabel_max_flow</tt></A>
|
||||
<li><a href="kolmogorov_max_flow.html"><tt>kolmogorov_max_flow</tt></a></li>
|
||||
<LI><A href="./maximum_matching.html"><tt>edmonds_maximum_cardinality_matching</tt></A>
|
||||
</OL>
|
||||
|
||||
@ -217,11 +218,11 @@
|
||||
</OL>
|
||||
</OL>
|
||||
|
||||
<LI>AT&T Graphviz Read/Write Utilities
|
||||
<OL>
|
||||
<LI><a href="./write-graphviz.html">write_graphviz</a>
|
||||
<LI><a href="read_graphviz.html">read_graphviz</a>
|
||||
</OL>
|
||||
<li>Graph Input/Output
|
||||
<ol>
|
||||
<li>AT&T Graphviz: <a href="read_graphviz.html">read_graphviz</a>, <a href="./write-graphviz.html">write_graphviz</a></li>
|
||||
<li>DIMACS Max-flow: <a href="read_dimacs.html">read_dimacs</a>, <a href="write_dimacs.html">write_dimacs</a></li>
|
||||
</ol></li>
|
||||
|
||||
<LI>Auxiliary Concepts, Classes, and Functions
|
||||
<OL>
|
||||
|
104
doc/write_dimacs.html
Normal file
104
doc/write_dimacs.html
Normal file
@ -0,0 +1,104 @@
|
||||
<HTML>
|
||||
|
||||
<!--
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
|
||||
<Head>
|
||||
<Title>Boost Graph Library: write_dimacs_max_flow</Title>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||
ALINK="#ff0000">
|
||||
<IMG SRC="../../../boost.png"
|
||||
ALT="C++ Boost" width="277" height="86">
|
||||
<BR Clear>
|
||||
|
||||
<H1><A NAME="sec:write_dimacs_max_flow">
|
||||
<TT>write_dimacs</TT>
|
||||
</H1>
|
||||
|
||||
|
||||
<pre>
|
||||
//outputs a graph with including edge_capacity properties to an std::ostream
|
||||
template < typename Graph, typename CapacityMap, typename IndexMap >
|
||||
void write_dimacs_max_flow(Graph& g,
|
||||
CapacityMap capacity,
|
||||
IndexMap idx,
|
||||
typename graph_traits<Graph>::vertex_descriptor& src,
|
||||
typename graph_traits<Graph>::vertex_descriptor& sink,
|
||||
std::ostream& out)
|
||||
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This method writes a BGL graph object as an max-flow problem into an output stream in extended dimacs format (see <a href="http://www.avglab.com/andrew/CATS/maxflow_formats.htm"><TT>Goldbergs site</TT></a> for more information).
|
||||
The output can be read in again using the <a href="../../../boost/graph/read_dimacs.hpp"><TT>boost/graph/read_dimacs.hpp</TT></a> method.
|
||||
|
||||
<H3>Where Defined</H3>
|
||||
|
||||
<P>
|
||||
<a href="../../../boost/graph/write_dimacs.hpp"><TT>boost/graph/write_dimacs.hpp</TT></a>
|
||||
|
||||
<h3>Parameters</h3>
|
||||
IN: <tt>Graph& g</tt>
|
||||
<blockquote>
|
||||
A directed or undirected graph. The graph's type must be a model of
|
||||
<a href="./VertexListGraph.html">VertexListGraph</a> and <a href="./EdgeListGraph.html">EdgeListGraph</a>, as num_vertices(Graph) and num_edges(Graph) is used inside. <a href="#1">[1]</a>
|
||||
</blockquote>
|
||||
|
||||
IN: <tt>CapacityMap capacity</tt>
|
||||
<blockquote>
|
||||
A property map that models <a href="../../property_map/ReadablePropertyMap.html">Readable Property Map</a> whose key type is the edge descriptor of the graph and whose value type can be written to a stream. <br>
|
||||
</blockquote>
|
||||
|
||||
IN: <tt>IndexMap epw</tt>
|
||||
<blockquote>
|
||||
A property map that models <a href="../../property_map/ReadablePropertyMap.html">Readable Property Map</a> whose key type is the vertex descriptor of the graph and whose value type can be written to a stream. <br>
|
||||
</blockquote>
|
||||
|
||||
OUT: <tt>std::ostream& out</tt>
|
||||
<blockquote>
|
||||
A standard <tt>std::ostream</tt> object.
|
||||
</blockquote>
|
||||
|
||||
<H3>
|
||||
Example
|
||||
</H3>
|
||||
A short <a href="../example/read_write_dimacs-eg.cpp">example</a> which uses read_dimacs and write_dimacs is located in the examples directory.
|
||||
|
||||
<h3>See Also</h3>
|
||||
|
||||
<a href="./read_dimacs.html"><tt>read_dimacs</tt></a>
|
||||
|
||||
<h3>Notes</h3>
|
||||
<a name="1">[1]</a> As num_edges() and num_vertices() is used inside which returns values for the unfiltered graph (instead of the filtered), this method cannot be used with a <a href="./filtered_graph.html">filtered_graph</a>See <a href="./filtered_graph.html#2">filtered_graph Note [2]</a> for the reason.
|
||||
</BODY>
|
||||
</HTML>
|
112
example/kolmogorov-eg.cpp
Normal file
112
example/kolmogorov-eg.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/graph/kolmogorov_max_flow.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/read_dimacs.hpp>
|
||||
#include <boost/graph/graph_utility.hpp>
|
||||
|
||||
// Use a DIMACS network flow file as stdin.
|
||||
// kolmogorov-eg < max_flow.dat
|
||||
//
|
||||
// Sample output:
|
||||
// c The total flow:
|
||||
// s 13
|
||||
//
|
||||
// c flow values:
|
||||
// f 0 6 3
|
||||
// f 0 1 6
|
||||
// f 0 2 4
|
||||
// f 1 5 1
|
||||
// f 1 0 0
|
||||
// f 1 3 5
|
||||
// f 2 4 4
|
||||
// f 2 3 0
|
||||
// f 2 0 0
|
||||
// f 3 7 5
|
||||
// f 3 2 0
|
||||
// f 3 1 0
|
||||
// f 4 5 0
|
||||
// f 4 6 4
|
||||
// f 5 4 0
|
||||
// f 5 7 1
|
||||
// f 6 7 7
|
||||
// f 6 4 0
|
||||
// f 7 6 0
|
||||
// f 7 5 0
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
typedef adjacency_list_traits < vecS, vecS, directedS > Traits;
|
||||
typedef adjacency_list < vecS, vecS, directedS,
|
||||
property < vertex_name_t, std::string,
|
||||
property < vertex_index_t, long,
|
||||
property < vertex_color_t, boost::default_color_type,
|
||||
property < vertex_distance_t, long,
|
||||
property < vertex_predecessor_t, Traits::edge_descriptor > > > > >,
|
||||
|
||||
property < edge_capacity_t, long,
|
||||
property < edge_residual_capacity_t, long,
|
||||
property < edge_reverse_t, Traits::edge_descriptor > > > > Graph;
|
||||
|
||||
Graph g;
|
||||
property_map < Graph, edge_capacity_t >::type
|
||||
capacity = get(edge_capacity, g);
|
||||
property_map < Graph, edge_residual_capacity_t >::type
|
||||
residual_capacity = get(edge_residual_capacity, g);
|
||||
property_map < Graph, edge_reverse_t >::type rev = get(edge_reverse, g);
|
||||
Traits::vertex_descriptor s, t;
|
||||
read_dimacs_max_flow(g, capacity, rev, s, t);
|
||||
|
||||
std::vector<default_color_type> color(num_vertices(g));
|
||||
std::vector<long> distance(num_vertices(g));
|
||||
long flow = kolmogorov_max_flow(g ,s, t);
|
||||
|
||||
std::cout << "c The total flow:" << std::endl;
|
||||
std::cout << "s " << flow << std::endl << std::endl;
|
||||
|
||||
std::cout << "c flow values:" << std::endl;
|
||||
graph_traits < Graph >::vertex_iterator u_iter, u_end;
|
||||
graph_traits < Graph >::out_edge_iterator ei, e_end;
|
||||
for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
|
||||
for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
|
||||
if (capacity[*ei] > 0)
|
||||
std::cout << "f " << *u_iter << " " << target(*ei, g) << " "
|
||||
<< (capacity[*ei] - residual_capacity[*ei]) << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
104
example/max_flow4.dat
Normal file
104
example/max_flow4.dat
Normal file
@ -0,0 +1,104 @@
|
||||
c Random Network
|
||||
p max 100 100
|
||||
n 1 s
|
||||
n 100 t
|
||||
a 27 24 37
|
||||
a 39 72 27
|
||||
a 2 5 35
|
||||
a 69 66 40
|
||||
a 56 32 33
|
||||
a 68 46 30
|
||||
a 4 5 46
|
||||
a 9 79 17
|
||||
a 14 16 23
|
||||
a 48 19 27
|
||||
a 21 24 39
|
||||
a 29 38 18
|
||||
a 15 70 7
|
||||
a 26 46 23
|
||||
a 50 14 31
|
||||
a 72 75 20
|
||||
a 66 26 38
|
||||
a 75 5 33
|
||||
a 77 6 6
|
||||
a 70 9 29
|
||||
a 14 79 4
|
||||
a 10 88 37
|
||||
a 48 61 8
|
||||
a 70 34 21
|
||||
a 6 46 4
|
||||
a 31 96 22
|
||||
a 16 98 45
|
||||
a 31 1 49
|
||||
a 6 61 38
|
||||
a 8 20 19
|
||||
a 76 81 26
|
||||
a 32 71 16
|
||||
a 37 36 10
|
||||
a 84 22 30
|
||||
a 2 3 48
|
||||
a 36 51 28
|
||||
a 15 2 19
|
||||
a 33 3 32
|
||||
a 54 66 14
|
||||
a 19 25 18
|
||||
a 93 68 12
|
||||
a 11 23 17
|
||||
a 18 58 23
|
||||
a 6 18 32
|
||||
a 1 4 30
|
||||
a 11 13 36
|
||||
a 53 6 44
|
||||
a 88 66 4
|
||||
a 48 78 9
|
||||
a 80 72 42
|
||||
a 5 44 11
|
||||
a 9 27 46
|
||||
a 38 1 2
|
||||
a 87 67 25
|
||||
a 95 6 48
|
||||
a 93 72 23
|
||||
a 97 85 49
|
||||
a 36 32 47
|
||||
a 28 4 41
|
||||
a 63 24 4
|
||||
a 29 56 9
|
||||
a 3 7 27
|
||||
a 8 1 21
|
||||
a 4 8 32
|
||||
a 3 2 6
|
||||
a 5 4 25
|
||||
a 48 10 7
|
||||
a 85 41 21
|
||||
a 4 28 44
|
||||
a 70 97 13
|
||||
a 5 56 37
|
||||
a 8 15 6
|
||||
a 80 26 24
|
||||
a 18 13 34
|
||||
a 23 80 8
|
||||
a 9 55 33
|
||||
a 31 52 50
|
||||
a 20 10 7
|
||||
a 84 62 34
|
||||
a 29 43 6
|
||||
a 6 20 25
|
||||
a 80 58 15
|
||||
a 46 26 43
|
||||
a 74 51 42
|
||||
a 100 60 43
|
||||
a 39 88 35
|
||||
a 45 41 1
|
||||
a 25 65 31
|
||||
a 6 8 33
|
||||
a 100 51 40
|
||||
a 11 75 21
|
||||
a 1 14 46
|
||||
a 16 41 6
|
||||
a 53 45 50
|
||||
a 4 22 23
|
||||
a 14 83 6
|
||||
a 17 83 32
|
||||
a 100 83 1
|
||||
a 16 8 41
|
||||
a 57 17 44
|
6004
example/max_flow5.dat
Normal file
6004
example/max_flow5.dat
Normal file
File diff suppressed because it is too large
Load Diff
404
example/max_flow6.dat
Normal file
404
example/max_flow6.dat
Normal file
@ -0,0 +1,404 @@
|
||||
c Random Network
|
||||
p max 100 400
|
||||
n 1 s
|
||||
n 100 t
|
||||
a 74 44 94
|
||||
a 2 4 67
|
||||
a 34 45 100
|
||||
a 4 35 14
|
||||
a 25 28 62
|
||||
a 34 26 91
|
||||
a 10 90 25
|
||||
a 13 3 77
|
||||
a 58 24 19
|
||||
a 22 34 52
|
||||
a 61 34 20
|
||||
a 3 12 48
|
||||
a 80 54 80
|
||||
a 13 86 20
|
||||
a 2 5 7
|
||||
a 44 34 41
|
||||
a 5 1 32
|
||||
a 8 13 87
|
||||
a 20 31 90
|
||||
a 90 3 74
|
||||
a 37 47 69
|
||||
a 65 54 82
|
||||
a 89 66 1
|
||||
a 40 36 16
|
||||
a 1 19 40
|
||||
a 3 4 55
|
||||
a 3 11 35
|
||||
a 61 85 72
|
||||
a 47 66 70
|
||||
a 82 87 59
|
||||
a 33 74 75
|
||||
a 81 91 75
|
||||
a 2 12 7
|
||||
a 25 45 30
|
||||
a 20 18 56
|
||||
a 3 21 63
|
||||
a 9 10 26
|
||||
a 25 3 37
|
||||
a 3 63 23
|
||||
a 1 3 64
|
||||
a 4 13 50
|
||||
a 5 68 14
|
||||
a 38 73 56
|
||||
a 64 96 60
|
||||
a 65 89 30
|
||||
a 14 37 81
|
||||
a 97 53 56
|
||||
a 6 30 36
|
||||
a 10 9 41
|
||||
a 13 9 83
|
||||
a 15 6 47
|
||||
a 7 1 13
|
||||
a 37 73 6
|
||||
a 50 62 33
|
||||
a 99 1 58
|
||||
a 71 1 59
|
||||
a 95 7 91
|
||||
a 1 34 92
|
||||
a 45 67 22
|
||||
a 96 3 15
|
||||
a 7 39 84
|
||||
a 1 2 66
|
||||
a 4 3 12
|
||||
a 13 85 93
|
||||
a 3 1 5
|
||||
a 7 66 63
|
||||
a 21 92 73
|
||||
a 33 82 82
|
||||
a 43 82 32
|
||||
a 64 47 54
|
||||
a 98 90 37
|
||||
a 65 28 34
|
||||
a 2 73 41
|
||||
a 20 35 55
|
||||
a 71 31 25
|
||||
a 10 32 47
|
||||
a 94 99 37
|
||||
a 13 8 27
|
||||
a 100 13 79
|
||||
a 7 18 81
|
||||
a 40 71 64
|
||||
a 85 1 44
|
||||
a 18 7 67
|
||||
a 12 10 68
|
||||
a 59 32 38
|
||||
a 11 97 97
|
||||
a 35 26 17
|
||||
a 94 63 10
|
||||
a 87 1 47
|
||||
a 9 16 10
|
||||
a 37 29 14
|
||||
a 68 78 64
|
||||
a 81 96 47
|
||||
a 3 5 25
|
||||
a 3 6 1
|
||||
a 11 21 44
|
||||
a 34 12 6
|
||||
a 36 32 18
|
||||
a 86 44 26
|
||||
a 53 87 8
|
||||
a 48 13 93
|
||||
a 48 25 43
|
||||
a 97 37 82
|
||||
a 11 17 77
|
||||
a 89 86 57
|
||||
a 49 52 53
|
||||
a 49 59 86
|
||||
a 6 15 1
|
||||
a 24 43 100
|
||||
a 8 25 70
|
||||
a 29 13 17
|
||||
a 4 9 37
|
||||
a 6 10 48
|
||||
a 45 95 17
|
||||
a 61 76 56
|
||||
a 11 10 15
|
||||
a 23 63 67
|
||||
a 19 53 21
|
||||
a 19 56 71
|
||||
a 36 35 64
|
||||
a 63 8 90
|
||||
a 74 25 58
|
||||
a 54 77 50
|
||||
a 57 81 61
|
||||
a 28 54 79
|
||||
a 61 23 74
|
||||
a 12 23 8
|
||||
a 27 36 72
|
||||
a 60 72 37
|
||||
a 35 51 92
|
||||
a 54 11 24
|
||||
a 57 15 79
|
||||
a 2 3 55
|
||||
a 75 7 42
|
||||
a 39 83 64
|
||||
a 18 36 63
|
||||
a 61 5 79
|
||||
a 34 3 28
|
||||
a 16 96 5
|
||||
a 33 30 82
|
||||
a 33 38 27
|
||||
a 10 1 20
|
||||
a 40 45 48
|
||||
a 4 8 14
|
||||
a 36 73 28
|
||||
a 1 4 18
|
||||
a 12 4 13
|
||||
a 14 9 9
|
||||
a 100 35 33
|
||||
a 86 43 78
|
||||
a 59 43 75
|
||||
a 4 2 34
|
||||
a 23 12 63
|
||||
a 85 44 75
|
||||
a 28 56 48
|
||||
a 7 9 64
|
||||
a 35 52 58
|
||||
a 70 93 54
|
||||
a 93 41 100
|
||||
a 73 17 68
|
||||
a 4 6 47
|
||||
a 4 5 73
|
||||
a 5 15 4
|
||||
a 26 38 57
|
||||
a 7 14 82
|
||||
a 35 31 5
|
||||
a 47 62 96
|
||||
a 75 33 45
|
||||
a 58 15 12
|
||||
a 94 75 94
|
||||
a 87 60 28
|
||||
a 2 1 92
|
||||
a 4 12 84
|
||||
a 22 19 14
|
||||
a 27 38 16
|
||||
a 55 35 23
|
||||
a 50 79 84
|
||||
a 9 1 53
|
||||
a 39 12 68
|
||||
a 73 8 89
|
||||
a 1 5 81
|
||||
a 28 9 33
|
||||
a 58 26 40
|
||||
a 29 2 17
|
||||
a 75 6 3
|
||||
a 89 40 45
|
||||
a 15 64 68
|
||||
a 58 5 28
|
||||
a 9 22 12
|
||||
a 3 34 93
|
||||
a 87 10 97
|
||||
a 2 49 28
|
||||
a 14 48 83
|
||||
a 8 19 35
|
||||
a 13 59 93
|
||||
a 35 82 59
|
||||
a 8 58 81
|
||||
a 54 85 41
|
||||
a 31 10 100
|
||||
a 78 94 41
|
||||
a 25 84 48
|
||||
a 70 82 70
|
||||
a 2 10 60
|
||||
a 47 96 7
|
||||
a 6 34 63
|
||||
a 1 9 19
|
||||
a 27 87 47
|
||||
a 5 7 44
|
||||
a 11 4 89
|
||||
a 98 8 26
|
||||
a 28 25 69
|
||||
a 13 61 95
|
||||
a 16 97 73
|
||||
a 16 90 73
|
||||
a 1 72 82
|
||||
a 60 32 30
|
||||
a 5 3 38
|
||||
a 88 91 20
|
||||
a 3 70 97
|
||||
a 9 13 29
|
||||
a 19 54 25
|
||||
a 17 25 97
|
||||
a 37 46 2
|
||||
a 8 83 19
|
||||
a 42 96 97
|
||||
a 22 96 98
|
||||
a 25 20 32
|
||||
a 3 2 26
|
||||
a 29 100 9
|
||||
a 8 33 20
|
||||
a 35 30 16
|
||||
a 4 95 69
|
||||
a 84 63 33
|
||||
a 58 72 82
|
||||
a 12 6 39
|
||||
a 44 8 99
|
||||
a 23 13 54
|
||||
a 100 93 54
|
||||
a 56 41 50
|
||||
a 91 10 16
|
||||
a 11 58 100
|
||||
a 29 67 73
|
||||
a 7 68 98
|
||||
a 9 75 22
|
||||
a 75 92 96
|
||||
a 93 61 60
|
||||
a 30 31 100
|
||||
a 5 6 77
|
||||
a 11 30 36
|
||||
a 49 22 7
|
||||
a 59 53 20
|
||||
a 9 80 63
|
||||
a 46 99 58
|
||||
a 50 37 68
|
||||
a 21 8 67
|
||||
a 3 29 48
|
||||
a 3 88 5
|
||||
a 17 29 22
|
||||
a 13 51 34
|
||||
a 38 86 49
|
||||
a 82 33 38
|
||||
a 20 70 43
|
||||
a 6 5 29
|
||||
a 30 48 62
|
||||
a 94 83 97
|
||||
a 7 53 50
|
||||
a 64 21 4
|
||||
a 6 9 71
|
||||
a 80 33 69
|
||||
a 98 51 26
|
||||
a 11 1 23
|
||||
a 92 1 7
|
||||
a 69 29 36
|
||||
a 99 98 33
|
||||
a 4 7 84
|
||||
a 51 88 45
|
||||
a 75 78 30
|
||||
a 81 1 92
|
||||
a 62 38 71
|
||||
a 8 16 69
|
||||
a 41 49 27
|
||||
a 38 42 82
|
||||
a 22 66 77
|
||||
a 5 22 88
|
||||
a 27 30 67
|
||||
a 40 87 4
|
||||
a 78 100 95
|
||||
a 87 40 52
|
||||
a 32 75 92
|
||||
a 61 84 46
|
||||
a 26 9 85
|
||||
a 41 55 1
|
||||
a 24 10 39
|
||||
a 55 95 55
|
||||
a 85 75 63
|
||||
a 87 91 69
|
||||
a 67 24 93
|
||||
a 15 24 58
|
||||
a 7 27 90
|
||||
a 32 58 68
|
||||
a 23 26 79
|
||||
a 49 28 87
|
||||
a 6 3 72
|
||||
a 14 13 28
|
||||
a 20 7 74
|
||||
a 3 89 58
|
||||
a 5 2 39
|
||||
a 35 8 100
|
||||
a 12 24 18
|
||||
a 69 7 11
|
||||
a 96 9 61
|
||||
a 63 39 22
|
||||
a 84 30 43
|
||||
a 24 52 33
|
||||
a 80 26 9
|
||||
a 10 16 78
|
||||
a 21 34 18
|
||||
a 5 14 40
|
||||
a 18 1 14
|
||||
a 36 10 38
|
||||
a 79 56 25
|
||||
a 85 59 39
|
||||
a 64 32 27
|
||||
a 75 83 71
|
||||
a 2 67 10
|
||||
a 60 66 81
|
||||
a 14 8 83
|
||||
a 54 50 57
|
||||
a 12 2 37
|
||||
a 2 11 97
|
||||
a 61 70 83
|
||||
a 37 21 98
|
||||
a 19 64 18
|
||||
a 9 7 9
|
||||
a 11 39 84
|
||||
a 43 34 29
|
||||
a 3 14 74
|
||||
a 49 18 85
|
||||
a 33 91 89
|
||||
a 21 93 47
|
||||
a 15 46 93
|
||||
a 34 100 9
|
||||
a 63 12 40
|
||||
a 70 34 9
|
||||
a 39 63 57
|
||||
a 10 19 78
|
||||
a 54 47 95
|
||||
a 20 48 45
|
||||
a 8 15 84
|
||||
a 12 3 89
|
||||
a 71 48 71
|
||||
a 68 96 38
|
||||
a 6 18 4
|
||||
a 88 46 62
|
||||
a 48 44 99
|
||||
a 30 1 20
|
||||
a 24 23 46
|
||||
a 71 72 79
|
||||
a 99 44 92
|
||||
a 61 52 34
|
||||
a 29 3 11
|
||||
a 64 67 9
|
||||
a 72 15 61
|
||||
a 26 24 43
|
||||
a 29 46 36
|
||||
a 94 37 64
|
||||
a 95 71 99
|
||||
a 45 8 54
|
||||
a 85 53 95
|
||||
a 94 78 74
|
||||
a 74 65 83
|
||||
a 50 25 42
|
||||
a 25 4 53
|
||||
a 7 5 17
|
||||
a 25 42 66
|
||||
a 47 24 1
|
||||
a 80 13 66
|
||||
a 88 17 28
|
||||
a 18 30 30
|
||||
a 45 10 96
|
||||
a 95 18 36
|
||||
a 98 12 20
|
||||
a 1 30 65
|
||||
a 99 39 50
|
||||
a 1 6 98
|
||||
a 20 8 53
|
||||
a 28 8 47
|
||||
a 91 49 69
|
||||
a 72 12 33
|
||||
a 28 4 91
|
||||
a 39 8 28
|
||||
a 58 34 23
|
||||
a 27 88 21
|
||||
a 3 18 41
|
||||
a 14 18 50
|
||||
a 66 38 85
|
||||
a 76 66 83
|
||||
a 35 1 37
|
||||
a 89 88 92
|
||||
a 7 31 40
|
10004
example/max_flow7.dat
Normal file
10004
example/max_flow7.dat
Normal file
File diff suppressed because it is too large
Load Diff
8004
example/max_flow8.dat
Normal file
8004
example/max_flow8.dat
Normal file
File diff suppressed because it is too large
Load Diff
10004
example/max_flow9.dat
Normal file
10004
example/max_flow9.dat
Normal file
File diff suppressed because it is too large
Load Diff
123
example/read_write_dimacs-eg.cpp
Normal file
123
example/read_write_dimacs-eg.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/read_dimacs.hpp>
|
||||
#include <boost/graph/write_dimacs.hpp>
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* example which reads in a max-flow problem from std::cin, augments all paths from
|
||||
* source->NODE->sink and writes the graph back to std::cout
|
||||
*
|
||||
**************************************/
|
||||
|
||||
template <typename EdgeCapacityMap>
|
||||
struct zero_edge_capacity{
|
||||
|
||||
zero_edge_capacity() { }
|
||||
zero_edge_capacity(EdgeCapacityMap cap_map):m_cap_map(cap_map){};
|
||||
|
||||
template <typename Edge>
|
||||
bool operator() (const Edge& e) const {
|
||||
return get(m_cap_map, e) == 0 ;
|
||||
}
|
||||
|
||||
EdgeCapacityMap m_cap_map;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
typedef adjacency_list_traits < vecS, vecS, directedS > Traits;
|
||||
typedef adjacency_list < vecS, vecS, directedS,
|
||||
no_property,
|
||||
property < edge_capacity_t, long,
|
||||
property < edge_reverse_t, Traits::edge_descriptor > > > Graph;
|
||||
|
||||
typedef graph_traits<Graph>::out_edge_iterator out_edge_iterator;
|
||||
typedef graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
typedef graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
Graph g;
|
||||
|
||||
typedef property_map < Graph, edge_capacity_t >::type tCapMap;
|
||||
typedef tCapMap::value_type tCapMapValue;
|
||||
|
||||
typedef property_map < Graph, edge_reverse_t >::type tRevEdgeMap;
|
||||
|
||||
tCapMap capacity = get(edge_capacity, g);
|
||||
tRevEdgeMap rev = get(edge_reverse, g);
|
||||
|
||||
vertex_descriptor s, t;
|
||||
/*reading the graph from stdin*/
|
||||
read_dimacs_max_flow(g, capacity, rev, s, t, std::cin);
|
||||
|
||||
/*process graph*/
|
||||
tCapMapValue augmented_flow = 0;
|
||||
|
||||
//we take the source node and check for each outgoing edge e which has a target(p) if we can augment that path
|
||||
out_edge_iterator oei,oe_end;
|
||||
for(tie(oei, oe_end) = out_edges(s, g); oei != oe_end; ++oei){
|
||||
edge_descriptor from_source = *oei;
|
||||
vertex_descriptor v = target(from_source, g);
|
||||
edge_descriptor to_sink;
|
||||
bool is_there;
|
||||
tie(to_sink, is_there) = edge(v, t, g);
|
||||
if( is_there ){
|
||||
if( get(capacity, to_sink) > get(capacity, from_source) ){
|
||||
tCapMapValue to_augment = get(capacity, from_source);
|
||||
capacity[from_source] = 0;
|
||||
capacity[to_sink] -= to_augment;
|
||||
augmented_flow += to_augment;
|
||||
}else{
|
||||
tCapMapValue to_augment = get(capacity, to_sink);
|
||||
capacity[to_sink] = 0;
|
||||
capacity[from_source] -= to_augment;
|
||||
augmented_flow += to_augment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove edges with zero capacity (most of them are the reverse edges)
|
||||
zero_edge_capacity<tCapMap> filter(capacity);
|
||||
remove_edge_if(filter, g);
|
||||
|
||||
/*write the graph back to stdout */
|
||||
write_dimacs_max_flow(g, capacity, identity_property_map(),s, t, std::cout);
|
||||
//print flow we augmented to std::cerr
|
||||
std::cerr << "removed " << augmented_flow << " from SOURCE->NODE->SINK connects" <<std::endl;
|
||||
return 0;
|
||||
}
|
807
include/boost/graph/kolmogorov_max_flow.hpp
Normal file
807
include/boost/graph/kolmogorov_max_flow.hpp
Normal file
@ -0,0 +1,807 @@
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_KOLMOGOROV_MAX_FLOW_HPP
|
||||
#define BOOST_KOLMOGOROV_MAX_FLOW_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <iosfwd>
|
||||
#include <algorithm> // for std::min and std::max
|
||||
|
||||
#include <boost/pending/queue.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/property_map.hpp>
|
||||
#include <boost/none_t.hpp>
|
||||
#include <boost/graph/graph_concepts.hpp>
|
||||
#include <boost/graph/named_function_params.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
|
||||
template <class Graph,
|
||||
class EdgeCapacityMap,
|
||||
class ResidualCapacityEdgeMap,
|
||||
class ReverseEdgeMap,
|
||||
class PredecessorMap,
|
||||
class ColorMap,
|
||||
class DistanceMap,
|
||||
class IndexMap>
|
||||
class kolmogorov{
|
||||
typedef typename property_traits<EdgeCapacityMap>::value_type tEdgeVal;
|
||||
typedef graph_traits<Graph> tGraphTraits;
|
||||
typedef typename tGraphTraits::vertex_iterator vertex_iterator;
|
||||
typedef typename tGraphTraits::vertex_descriptor vertex_descriptor;
|
||||
typedef typename tGraphTraits::edge_descriptor edge_descriptor;
|
||||
typedef typename tGraphTraits::edge_iterator edge_iterator;
|
||||
typedef typename tGraphTraits::out_edge_iterator out_edge_iterator;
|
||||
typedef boost::queue<vertex_descriptor> tQueue; //queue of vertices, used in adoption-stage
|
||||
typedef typename property_traits<ColorMap>::value_type tColorValue;
|
||||
typedef color_traits<tColorValue> tColorTraits;
|
||||
typedef typename property_traits<DistanceMap>::value_type tDistanceVal;
|
||||
|
||||
public:
|
||||
kolmogorov(Graph& g,
|
||||
EdgeCapacityMap cap,
|
||||
ResidualCapacityEdgeMap res,
|
||||
ReverseEdgeMap rev,
|
||||
PredecessorMap pre,
|
||||
ColorMap color,
|
||||
DistanceMap dist,
|
||||
IndexMap idx,
|
||||
vertex_descriptor src,
|
||||
vertex_descriptor sink):
|
||||
m_g(g),
|
||||
m_index_map(idx),
|
||||
m_cap_map(cap),
|
||||
m_res_cap_map(res),
|
||||
m_rev_edge_map(rev),
|
||||
m_pre_map(pre),
|
||||
m_tree_map(color),
|
||||
m_dist_map(dist),
|
||||
m_source(src),
|
||||
m_sink(sink),
|
||||
m_active_nodes(),
|
||||
m_in_active_list_vec(num_vertices(g), false),
|
||||
m_in_active_list_map(make_iterator_property_map(m_in_active_list_vec.begin(), m_index_map)),
|
||||
m_has_parent_vec(num_vertices(g), false),
|
||||
m_has_parent_map(make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)),
|
||||
m_time_vec(num_vertices(g), 0),
|
||||
m_time_map(make_iterator_property_map(m_time_vec.begin(), m_index_map)),
|
||||
m_flow(0),
|
||||
m_time(1),
|
||||
m_last_grow_vertex(graph_traits<Graph>::null_vertex()){
|
||||
// initialize the color-map with gray-values
|
||||
vertex_iterator vi, v_end;
|
||||
for(tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi){
|
||||
set_tree(*vi, tColorTraits::gray());
|
||||
}
|
||||
// Initialize flow to zero which means initializing
|
||||
// the residual capacity equal to the capacity
|
||||
edge_iterator ei, e_end;
|
||||
for(tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) {
|
||||
m_res_cap_map[*ei] = m_cap_map[*ei];
|
||||
assert(m_rev_edge_map[m_rev_edge_map[*ei]] == *ei); //check if the reverse edge map is build up properly
|
||||
}
|
||||
//init the search trees with the two terminals
|
||||
set_tree(m_source, tColorTraits::white());
|
||||
set_tree(m_sink, tColorTraits::black());
|
||||
m_time_map[m_source] = 1;
|
||||
m_time_map[m_sink] = 1;
|
||||
}
|
||||
|
||||
~kolmogorov(){}
|
||||
|
||||
tEdgeVal max_flow(){
|
||||
//augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK
|
||||
augment_direct_paths();
|
||||
//start the main-loop
|
||||
while(true){
|
||||
bool path_found;
|
||||
edge_descriptor connecting_edge;
|
||||
tie(connecting_edge, path_found) = grow(); //find a path from source to sink
|
||||
if(!path_found){
|
||||
//we're finished, no more paths were found
|
||||
break;
|
||||
}
|
||||
++m_time;
|
||||
augment(connecting_edge); //augment that path
|
||||
adopt(); //rebuild search tree structure
|
||||
}
|
||||
return m_flow;
|
||||
}
|
||||
|
||||
//the complete class is protected, as we want access to members in derived test-class (see $(BOOST_ROOT)/libs/graph/test/kolmogorov_max_flow_test.cpp)
|
||||
protected:
|
||||
void augment_direct_paths(){
|
||||
//in a first step, we augment all direct paths from source->NODE->sink
|
||||
//and additionally paths from source->sink
|
||||
//this improves especially graphcuts for segmentation, as most of the nodes have source/sink connects
|
||||
//but shouldn't have an impact on other maxflow problems (this is done in grow() anyway)
|
||||
out_edge_iterator ei, e_end;
|
||||
for(tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei){
|
||||
edge_descriptor from_source = *ei;
|
||||
vertex_descriptor current_node = target(from_source, m_g);
|
||||
if(current_node == m_sink){
|
||||
tEdgeVal cap = m_res_cap_map[from_source];
|
||||
m_res_cap_map[from_source] = 0;
|
||||
m_flow += cap;
|
||||
continue;
|
||||
}
|
||||
edge_descriptor to_sink;
|
||||
bool is_there;
|
||||
tie(to_sink, is_there) = edge(current_node, m_sink, m_g);
|
||||
if(is_there){
|
||||
tEdgeVal cap_from_source = m_res_cap_map[from_source];
|
||||
tEdgeVal cap_to_sink = m_res_cap_map[to_sink];
|
||||
if(cap_from_source > cap_to_sink){
|
||||
set_tree(current_node, tColorTraits::white());
|
||||
add_active_node(current_node);
|
||||
set_edge_to_parent(current_node, from_source);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
//add stuff to flow and update residuals
|
||||
//we dont need to update reverse_edges, as incoming/outgoing edges to/from source/sink don't count for max-flow
|
||||
m_res_cap_map[from_source] -= cap_to_sink;
|
||||
m_res_cap_map[to_sink] = 0;
|
||||
m_flow += cap_to_sink;
|
||||
} else if(cap_to_sink > 0){
|
||||
set_tree(current_node, tColorTraits::black());
|
||||
add_active_node(current_node);
|
||||
set_edge_to_parent(current_node, to_sink);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
//add stuff to flow and update residuals
|
||||
//we dont need to update reverse_edges, as incoming/outgoing edges to/from source/sink don't count for max-flow
|
||||
m_res_cap_map[to_sink] -= cap_from_source;
|
||||
m_res_cap_map[from_source] = 0;
|
||||
m_flow += cap_from_source;
|
||||
}
|
||||
} else if(m_res_cap_map[from_source]){
|
||||
//there is no sink connect, so we can't augment this path
|
||||
//but to avoid adding m_source to the active nodes, we just activate this node and set the approciate things
|
||||
set_tree(current_node, tColorTraits::white());
|
||||
set_edge_to_parent(current_node, from_source);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
add_active_node(current_node);
|
||||
}
|
||||
}
|
||||
for(tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei){
|
||||
edge_descriptor to_sink = m_rev_edge_map[*ei];
|
||||
vertex_descriptor current_node = source(to_sink, m_g);
|
||||
if(m_res_cap_map[to_sink]){
|
||||
set_tree(current_node, tColorTraits::black());
|
||||
set_edge_to_parent(current_node, to_sink);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
add_active_node(current_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a pair of an edge and a boolean. if the bool is true, the edge is a connection of a found path from s->t , read "the link" and
|
||||
* source(returnVal, m_g) is the end of the path found in the source-tree
|
||||
* target(returnVal, m_g) is the beginning of the path found in the sink-tree
|
||||
*/
|
||||
std::pair<edge_descriptor, bool> grow(){
|
||||
assert(m_orphans.empty());
|
||||
vertex_descriptor current_node;
|
||||
while((current_node = get_next_active_node()) != graph_traits<Graph>::null_vertex()){ //if there is one
|
||||
assert(get_tree(current_node) != tColorTraits::gray() && (has_parent(current_node) || current_node==m_source || current_node==m_sink));
|
||||
if(get_tree(current_node) == tColorTraits::white()){
|
||||
//source tree growing
|
||||
out_edge_iterator ei, e_end;
|
||||
if(current_node != m_last_grow_vertex){
|
||||
m_last_grow_vertex = current_node;
|
||||
tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
|
||||
}
|
||||
for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){
|
||||
edge_descriptor out_edge = *m_last_grow_edge_it;
|
||||
if(m_res_cap_map[out_edge] > 0){ //check if we have capacity left on this edge
|
||||
vertex_descriptor other_node = target(out_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
|
||||
set_tree(other_node, tColorTraits::white()); //aquire other node to our search tree
|
||||
set_edge_to_parent(other_node, out_edge); //set us as parent
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1; //and update the distance-heuristic
|
||||
m_time_map[other_node] = m_time_map[current_node];
|
||||
add_active_node(other_node);
|
||||
} else if(get_tree(other_node) == tColorTraits::white()){
|
||||
if(is_closer_to_terminal(current_node, other_node)){ //we do this to get shorter paths. check if we are nearer to the source as its parent is
|
||||
set_edge_to_parent(other_node, out_edge);
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1;
|
||||
m_time_map[other_node] = m_time_map[current_node];
|
||||
}
|
||||
} else{
|
||||
assert(get_tree(other_node)==tColorTraits::black());
|
||||
//kewl, found a path from one to the other search tree, return the connecting edge in src->sink dir
|
||||
return std::make_pair(out_edge, true);
|
||||
}
|
||||
}
|
||||
} //for all out-edges
|
||||
} //source-tree-growing
|
||||
else{
|
||||
assert(get_tree(current_node) == tColorTraits::black());
|
||||
out_edge_iterator ei, e_end;
|
||||
if(current_node != m_last_grow_vertex){
|
||||
m_last_grow_vertex = current_node;
|
||||
tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
|
||||
}
|
||||
for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){
|
||||
edge_descriptor in_edge = m_rev_edge_map[*m_last_grow_edge_it];
|
||||
if(m_res_cap_map[in_edge] > 0){ //check if there is capacity left
|
||||
vertex_descriptor other_node = source(in_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
|
||||
set_tree(other_node, tColorTraits::black()); //aquire that node to our search tree
|
||||
set_edge_to_parent(other_node, in_edge); //set us as parent
|
||||
add_active_node(other_node); //activate that node
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1; //set its distance
|
||||
m_time_map[other_node] = m_time_map[current_node]; //and time
|
||||
} else if(get_tree(other_node) == tColorTraits::black()){
|
||||
if(is_closer_to_terminal(current_node, other_node)){
|
||||
//we are closer to the sink than its parent is, so we "adopt" him
|
||||
set_edge_to_parent(other_node, in_edge);
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1;
|
||||
m_time_map[other_node] = m_time_map[current_node];
|
||||
}
|
||||
} else{
|
||||
assert(get_tree(other_node)==tColorTraits::white());
|
||||
//kewl, found a path from one to the other search tree, return the connecting edge in src->sink dir
|
||||
return std::make_pair(in_edge, true);
|
||||
}
|
||||
}
|
||||
} //for all out-edges
|
||||
} //sink-tree growing
|
||||
//all edges of that node are processed, and no more paths were found. so remove if from the front of the active queue
|
||||
finish_node(current_node);
|
||||
} //while active_nodes not empty
|
||||
return std::make_pair(edge_descriptor(), false); //no active nodes anymore and no path found, we're done
|
||||
}
|
||||
|
||||
/**
|
||||
* augments path from s->t and updates residual graph
|
||||
* source(e, m_g) is the end of the path found in the source-tree
|
||||
* target(e, m_g) is the beginning of the path found in the sink-tree
|
||||
* this phase generates orphans on satured edges, if the attached verts are from different search-trees
|
||||
* orphans are ordered in distance to sink/source. first the farest from the source are front_inserted into the orphans list,
|
||||
* and after that the sink-tree-orphans are front_inserted. when going to adoption stage the orphans are popped_front, and so we process the nearest
|
||||
* verts to the terminals first
|
||||
*/
|
||||
void augment(edge_descriptor e){
|
||||
assert(get_tree(target(e, m_g)) == tColorTraits::black());
|
||||
assert(get_tree(source(e, m_g)) == tColorTraits::white());
|
||||
assert(m_orphans.empty());
|
||||
|
||||
const tEdgeVal bottleneck = find_bottleneck(e);
|
||||
//now we push the found flow through the path
|
||||
//for each edge we saturate we have to look for the verts that belong to that edge, one of them becomes an orphans
|
||||
//now process the connecting edge
|
||||
m_res_cap_map[e] -= bottleneck;
|
||||
assert(m_res_cap_map[e] >= 0);
|
||||
m_res_cap_map[m_rev_edge_map[e]] += bottleneck;
|
||||
|
||||
//now we follow the path back to the source
|
||||
vertex_descriptor current_node = source(e, m_g);
|
||||
while(current_node != m_source){
|
||||
edge_descriptor pred = get_edge_to_parent(current_node);
|
||||
m_res_cap_map[pred] -= bottleneck;
|
||||
assert(m_res_cap_map[pred] >= 0);
|
||||
m_res_cap_map[m_rev_edge_map[pred]] += bottleneck;
|
||||
if(m_res_cap_map[pred] == 0){
|
||||
set_no_parent(current_node);
|
||||
m_orphans.push_front(current_node);
|
||||
}
|
||||
current_node = source(pred, m_g);
|
||||
}
|
||||
//then go forward in the sink-tree
|
||||
current_node = target(e, m_g);
|
||||
while(current_node != m_sink){
|
||||
edge_descriptor pred = get_edge_to_parent(current_node);
|
||||
m_res_cap_map[pred] -= bottleneck;
|
||||
assert(m_res_cap_map[pred] >= 0);
|
||||
m_res_cap_map[m_rev_edge_map[pred]] += bottleneck;
|
||||
if(m_res_cap_map[pred] == 0){
|
||||
set_no_parent(current_node);
|
||||
m_orphans.push_front(current_node);
|
||||
}
|
||||
current_node = target(pred, m_g);
|
||||
}
|
||||
//and add it to the max-flow
|
||||
m_flow += bottleneck;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the bottleneck of a s->t path (end_of_path is last vertex in source-tree, begin_of_path is first vertex in sink-tree)
|
||||
*/
|
||||
inline tEdgeVal find_bottleneck(edge_descriptor e){
|
||||
BOOST_USING_STD_MIN();
|
||||
tEdgeVal minimum_cap = m_res_cap_map[e];
|
||||
vertex_descriptor current_node = source(e, m_g);
|
||||
//first go back in the source tree
|
||||
while(current_node != m_source){
|
||||
edge_descriptor pred = get_edge_to_parent(current_node);
|
||||
minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, m_res_cap_map[pred]);
|
||||
current_node = source(pred, m_g);
|
||||
}
|
||||
//then go forward in the sink-tree
|
||||
current_node = target(e, m_g);
|
||||
while(current_node != m_sink){
|
||||
edge_descriptor pred = get_edge_to_parent(current_node);
|
||||
minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, m_res_cap_map[pred]);
|
||||
current_node = target(pred, m_g);
|
||||
}
|
||||
return minimum_cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* rebuild search trees
|
||||
* empty the queue of orphans, and find new parents for them or just drop them from the search trees
|
||||
*/
|
||||
void adopt(){
|
||||
while(!m_orphans.empty() || !m_child_orphans.empty()){
|
||||
vertex_descriptor current_node;
|
||||
if(m_child_orphans.empty()){
|
||||
//get the next orphan from the main-queue and remove it
|
||||
current_node = m_orphans.front();
|
||||
m_orphans.pop_front();
|
||||
} else{
|
||||
current_node = m_child_orphans.front();
|
||||
m_child_orphans.pop();
|
||||
}
|
||||
if(get_tree(current_node) == tColorTraits::white()){
|
||||
//we're in the source-tree
|
||||
tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
|
||||
edge_descriptor new_parent_edge;
|
||||
out_edge_iterator ei, e_end;
|
||||
for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
|
||||
const edge_descriptor in_edge = m_rev_edge_map[*ei];
|
||||
assert(target(in_edge, m_g) == current_node); //we should be the target of this edge
|
||||
if(m_res_cap_map[in_edge] > 0){
|
||||
vertex_descriptor other_node = source(in_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::white() && has_source_connect(other_node)){
|
||||
if(m_dist_map[other_node] < min_distance){
|
||||
min_distance = m_dist_map[other_node];
|
||||
new_parent_edge = in_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
|
||||
set_edge_to_parent(current_node, new_parent_edge);
|
||||
m_dist_map[current_node] = min_distance + 1;
|
||||
m_time_map[current_node] = m_time;
|
||||
} else{
|
||||
m_time_map[current_node] = 0;
|
||||
for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
|
||||
edge_descriptor in_edge = m_rev_edge_map[*ei];
|
||||
vertex_descriptor other_node = source(in_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::white() && has_parent(other_node)){
|
||||
if(m_res_cap_map[in_edge] > 0){
|
||||
add_active_node(other_node);
|
||||
}
|
||||
if(source(get_edge_to_parent(other_node), m_g) == current_node){
|
||||
//we are the parent of that node
|
||||
//it has to find a new parent, too
|
||||
set_no_parent(other_node);
|
||||
m_child_orphans.push(other_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
set_tree(current_node, tColorTraits::gray());
|
||||
} //no parent found
|
||||
} //source-tree-adoption
|
||||
else{
|
||||
//now we should be in the sink-tree, check that...
|
||||
assert(get_tree(current_node) == tColorTraits::black());
|
||||
out_edge_iterator ei, e_end;
|
||||
edge_descriptor new_parent_edge;
|
||||
tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
|
||||
for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
|
||||
const edge_descriptor out_edge = *ei;
|
||||
if(m_res_cap_map[out_edge] > 0){
|
||||
const vertex_descriptor other_node = target(out_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::black() && has_sink_connect(other_node))
|
||||
if(m_dist_map[other_node] < min_distance){
|
||||
min_distance = m_dist_map[other_node];
|
||||
new_parent_edge = out_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
|
||||
set_edge_to_parent(current_node, new_parent_edge);
|
||||
m_dist_map[current_node] = min_distance + 1;
|
||||
m_time_map[current_node] = m_time;
|
||||
} else{
|
||||
m_time_map[current_node] = 0;
|
||||
for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
|
||||
const edge_descriptor out_edge = *ei;
|
||||
const vertex_descriptor other_node = target(out_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::black() && has_parent(other_node)){
|
||||
if(m_res_cap_map[out_edge] > 0){
|
||||
add_active_node(other_node);
|
||||
}
|
||||
if(target(get_edge_to_parent(other_node), m_g) == current_node){
|
||||
//we were it's parent, so it has to find a new one, too
|
||||
set_no_parent(other_node);
|
||||
m_child_orphans.push(other_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
set_tree(current_node, tColorTraits::gray());
|
||||
} //no parent found
|
||||
} //sink-tree adoption
|
||||
} //while !orphans.empty()
|
||||
} //adopt
|
||||
|
||||
/**
|
||||
* return next active vertex if there is one, otherwise a null_vertex
|
||||
*/
|
||||
inline vertex_descriptor get_next_active_node(){
|
||||
while(true){
|
||||
if(m_active_nodes.empty())
|
||||
return graph_traits<Graph>::null_vertex();
|
||||
vertex_descriptor v = m_active_nodes.front();
|
||||
|
||||
if(!has_parent(v) && v != m_source && v != m_sink){ //if it has no parent, this node can't be active(if its not source or sink)
|
||||
m_active_nodes.pop();
|
||||
m_in_active_list_map[v] = false;
|
||||
} else{
|
||||
assert(get_tree(v) == tColorTraits::white() || get_tree(v) == tColorTraits::black());
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adds v as an active vertex, but only if its not in the list already
|
||||
*/
|
||||
inline void add_active_node(vertex_descriptor v){
|
||||
assert(get_tree(v) != tColorTraits::gray());
|
||||
if(m_in_active_list_map[v]){
|
||||
return;
|
||||
} else{
|
||||
m_in_active_list_map[v] = true;
|
||||
m_active_nodes.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
inline void finish_node(vertex_descriptor v){
|
||||
assert(m_active_nodes.front() == v);
|
||||
m_active_nodes.pop();
|
||||
m_in_active_list_map[v] = false;
|
||||
m_last_grow_vertex = graph_traits<Graph>::null_vertex();
|
||||
}
|
||||
|
||||
/**
|
||||
* removes a vertex from the queue of active nodes (actually this does nothing,
|
||||
* but checks if this node has no parent edge, as this is the criteria for beeing no more active)
|
||||
*/
|
||||
inline void remove_active_node(vertex_descriptor v){
|
||||
assert(!has_parent(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the search tree of v; tColorValue::white() for source tree, black() for sink tree, gray() for no tree
|
||||
*/
|
||||
inline tColorValue get_tree(vertex_descriptor v) const {
|
||||
return m_tree_map[v];
|
||||
}
|
||||
|
||||
/**
|
||||
* sets search tree of v; tColorValue::white() for source tree, black() for sink tree, gray() for no tree
|
||||
*/
|
||||
inline void set_tree(vertex_descriptor v, tColorValue t){
|
||||
m_tree_map[v] = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns edge to parent vertex of v;
|
||||
*/
|
||||
inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const{
|
||||
return m_pre_map[v];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the edge stored in m_pre_map[v] is a valid entry
|
||||
*/
|
||||
inline bool has_parent(vertex_descriptor v) const{
|
||||
return m_has_parent_map[v];
|
||||
}
|
||||
|
||||
/**
|
||||
* sets edge to parent vertex of v;
|
||||
*/
|
||||
inline void set_edge_to_parent(vertex_descriptor v, edge_descriptor f_edge_to_parent){
|
||||
assert(m_res_cap_map[f_edge_to_parent] > 0);
|
||||
m_pre_map[v] = f_edge_to_parent;
|
||||
m_has_parent_map[v] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the edge to parent of v (this is done by invalidating the entry an additional map)
|
||||
*/
|
||||
inline void set_no_parent(vertex_descriptor v){
|
||||
m_has_parent_map[v] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if vertex v has a connect to the sink-vertex (@var m_sink)
|
||||
* @param v the vertex which is checked
|
||||
* @return true if a path to the sink was found, false if not
|
||||
*/
|
||||
inline bool has_sink_connect(vertex_descriptor v){
|
||||
tDistanceVal current_distance = 0;
|
||||
vertex_descriptor current_vertex = v;
|
||||
while(true){
|
||||
if(m_time_map[current_vertex] == m_time){
|
||||
//we found a node which was already checked this round. use it for distance calculations
|
||||
current_distance += m_dist_map[current_vertex];
|
||||
break;
|
||||
}
|
||||
if(current_vertex == m_sink){
|
||||
m_time_map[m_sink] = m_time;
|
||||
break;
|
||||
}
|
||||
if(has_parent(current_vertex)){
|
||||
//it has a parent, so get it
|
||||
current_vertex = target(get_edge_to_parent(current_vertex), m_g);
|
||||
++current_distance;
|
||||
} else{
|
||||
//no path found
|
||||
return false;
|
||||
}
|
||||
}
|
||||
current_vertex=v;
|
||||
while(m_time_map[current_vertex] != m_time){
|
||||
m_dist_map[current_vertex] = current_distance--;
|
||||
m_time_map[current_vertex] = m_time;
|
||||
current_vertex = target(get_edge_to_parent(current_vertex), m_g);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if vertex v has a connect to the source-vertex (@var m_source)
|
||||
* @param v the vertex which is checked
|
||||
* @return true if a path to the source was found, false if not
|
||||
*/
|
||||
inline bool has_source_connect(vertex_descriptor v){
|
||||
tDistanceVal current_distance = 0;
|
||||
vertex_descriptor current_vertex = v;
|
||||
while(true){
|
||||
if(m_time_map[current_vertex] == m_time){
|
||||
//we found a node which was already checked this round. use it for distance calculations
|
||||
current_distance += m_dist_map[current_vertex];
|
||||
break;
|
||||
}
|
||||
if(current_vertex == m_source){
|
||||
m_time_map[m_source] = m_time;
|
||||
break;
|
||||
}
|
||||
if(has_parent(current_vertex)){
|
||||
//it has a parent, so get it
|
||||
current_vertex = source(get_edge_to_parent(current_vertex), m_g);
|
||||
++current_distance;
|
||||
} else{
|
||||
//no path found
|
||||
return false;
|
||||
}
|
||||
}
|
||||
current_vertex=v;
|
||||
while(m_time_map[current_vertex] != m_time){
|
||||
m_dist_map[current_vertex] = current_distance-- ;
|
||||
m_time_map[current_vertex] = m_time;
|
||||
current_vertex = source(get_edge_to_parent(current_vertex), m_g);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true, if p is closer to a terminal than q
|
||||
*/
|
||||
inline bool is_closer_to_terminal(vertex_descriptor p, vertex_descriptor q){
|
||||
//checks the timestamps first, to build no cycles, and after that the real distance
|
||||
return (m_time_map[q] <= m_time_map[p] && m_dist_map[q] > m_dist_map[p]+1);
|
||||
}
|
||||
|
||||
////////
|
||||
// member vars
|
||||
////////
|
||||
Graph& m_g;
|
||||
IndexMap m_index_map;
|
||||
EdgeCapacityMap m_cap_map;
|
||||
ResidualCapacityEdgeMap m_res_cap_map;
|
||||
ReverseEdgeMap m_rev_edge_map;
|
||||
PredecessorMap m_pre_map; //stores paths found in the growth stage
|
||||
ColorMap m_tree_map; //maps each vertex into one of the two search tree or none (gray())
|
||||
DistanceMap m_dist_map; //stores distance to source/sink nodes
|
||||
vertex_descriptor m_source;
|
||||
vertex_descriptor m_sink;
|
||||
|
||||
tQueue m_active_nodes;
|
||||
std::vector<bool> m_in_active_list_vec;
|
||||
iterator_property_map<std::vector<bool>::iterator, IndexMap> m_in_active_list_map;
|
||||
|
||||
std::list<vertex_descriptor> m_orphans;
|
||||
tQueue m_child_orphans; // we use a second queuqe for child orphans, as they are FIFO processed
|
||||
|
||||
std::vector<bool> m_has_parent_vec;
|
||||
iterator_property_map<std::vector<bool>::iterator, IndexMap> m_has_parent_map;
|
||||
|
||||
std::vector<long> m_time_vec; //timestamp of each node, used for sink/source-path calculations
|
||||
iterator_property_map<std::vector<long>::iterator, IndexMap> m_time_map;
|
||||
tEdgeVal m_flow;
|
||||
long m_time;
|
||||
vertex_descriptor m_last_grow_vertex;
|
||||
out_edge_iterator m_last_grow_edge_it;
|
||||
out_edge_iterator m_last_grow_edge_end;
|
||||
};
|
||||
} //namespace detail
|
||||
|
||||
/**
|
||||
* non-named-parameter version, given everything
|
||||
* this is the catch all version
|
||||
*/
|
||||
template <class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap,
|
||||
class PredecessorMap, class ColorMap, class DistanceMap, class IndexMap>
|
||||
typename property_traits<CapacityEdgeMap>::value_type
|
||||
kolmogorov_max_flow
|
||||
(Graph& g,
|
||||
CapacityEdgeMap cap,
|
||||
ResidualCapacityEdgeMap res_cap,
|
||||
ReverseEdgeMap rev_map,
|
||||
PredecessorMap pre_map,
|
||||
ColorMap color,
|
||||
DistanceMap dist,
|
||||
IndexMap idx,
|
||||
typename graph_traits<Graph>::vertex_descriptor src,
|
||||
typename graph_traits<Graph>::vertex_descriptor sink
|
||||
)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
//as this method is the last one before we instantiate the solver, we do the concept checks here
|
||||
function_requires<VertexListGraphConcept<Graph> >(); //to have vertices(), num_vertices(),
|
||||
function_requires<EdgeListGraphConcept<Graph> >(); //to have edges()
|
||||
function_requires<IncidenceGraphConcept<Graph> >(); //to have source(), target() and out_edges()
|
||||
function_requires<LvaluePropertyMapConcept<CapacityEdgeMap, edge_descriptor> >(); //read flow-values from edges
|
||||
function_requires<Mutable_LvaluePropertyMapConcept<ResidualCapacityEdgeMap, edge_descriptor> >(); //write flow-values to residuals
|
||||
function_requires<LvaluePropertyMapConcept<ReverseEdgeMap, edge_descriptor> >(); //read out reverse edges
|
||||
function_requires<Mutable_LvaluePropertyMapConcept<PredecessorMap, vertex_descriptor> >(); //store predecessor there
|
||||
function_requires<Mutable_LvaluePropertyMapConcept<ColorMap, vertex_descriptor> >(); //write corresponding tree
|
||||
function_requires<Mutable_LvaluePropertyMapConcept<DistanceMap, vertex_descriptor> >(); //write distance to source/sink
|
||||
function_requires<ReadablePropertyMapConcept<IndexMap, vertex_descriptor> >(); //get index 0...|V|-1
|
||||
assert(num_vertices(g) >= 2 && src != sink);
|
||||
detail::kolmogorov<Graph, CapacityEdgeMap, ResidualCapacityEdgeMap, ReverseEdgeMap, PredecessorMap, ColorMap, DistanceMap, IndexMap>
|
||||
algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink);
|
||||
return algo.max_flow();
|
||||
}
|
||||
|
||||
/**
|
||||
* non-named-parameter version, given: capacity, residucal_capacity, reverse_edges, and an index map.
|
||||
*/
|
||||
template <class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class IndexMap>
|
||||
typename property_traits<CapacityEdgeMap>::value_type
|
||||
kolmogorov_max_flow
|
||||
(Graph& g,
|
||||
CapacityEdgeMap cap,
|
||||
ResidualCapacityEdgeMap res_cap,
|
||||
ReverseEdgeMap rev,
|
||||
IndexMap idx,
|
||||
typename graph_traits<Graph>::vertex_descriptor src,
|
||||
typename graph_traits<Graph>::vertex_descriptor sink)
|
||||
{
|
||||
typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
|
||||
std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
|
||||
std::vector<default_color_type> color_vec(n_verts);
|
||||
std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
|
||||
return kolmogorov_max_flow
|
||||
(g, cap, res_cap, rev,
|
||||
make_iterator_property_map(predecessor_vec.begin(), idx),
|
||||
make_iterator_property_map(color_vec.begin(), idx),
|
||||
make_iterator_property_map(distance_vec.begin(), idx),
|
||||
idx, src, sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* non-named-parameter version, some given: capacity, residual_capacity, reverse_edges, color_map and an index map.
|
||||
* Use this if you are interested in the minimum cut, as the color map provides that info
|
||||
*/
|
||||
template <class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class ColorMap, class IndexMap>
|
||||
typename property_traits<CapacityEdgeMap>::value_type
|
||||
kolmogorov_max_flow
|
||||
(Graph& g,
|
||||
CapacityEdgeMap cap,
|
||||
ResidualCapacityEdgeMap res_cap,
|
||||
ReverseEdgeMap rev,
|
||||
ColorMap color,
|
||||
IndexMap idx,
|
||||
typename graph_traits<Graph>::vertex_descriptor src,
|
||||
typename graph_traits<Graph>::vertex_descriptor sink)
|
||||
{
|
||||
typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
|
||||
std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
|
||||
std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
|
||||
|
||||
return kolmogorov_max_flow
|
||||
(g, cap, res_cap, rev,
|
||||
make_iterator_property_map(predecessor_vec.begin(), idx),
|
||||
color,
|
||||
make_iterator_property_map(distance_vec.begin(), idx),
|
||||
idx, src, sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* named-parameter version, some given
|
||||
*/
|
||||
template <class Graph, class P, class T, class R>
|
||||
typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
|
||||
kolmogorov_max_flow
|
||||
(Graph& g,
|
||||
typename graph_traits<Graph>::vertex_descriptor src,
|
||||
typename graph_traits<Graph>::vertex_descriptor sink,
|
||||
const bgl_named_params<P, T, R>& params)
|
||||
{
|
||||
return kolmogorov_max_flow(g,
|
||||
choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
|
||||
choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity),
|
||||
choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
|
||||
choose_pmap(get_param(params, vertex_predecessor), g, vertex_predecessor),
|
||||
choose_pmap(get_param(params, vertex_color), g, vertex_color),
|
||||
choose_pmap(get_param(params, vertex_distance), g, vertex_distance),
|
||||
choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
|
||||
src, sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* named-parameter version, none given
|
||||
*/
|
||||
template <class Graph>
|
||||
typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
|
||||
kolmogorov_max_flow
|
||||
(Graph& g,
|
||||
typename graph_traits<Graph>::vertex_descriptor src,
|
||||
typename graph_traits<Graph>::vertex_descriptor sink)
|
||||
{
|
||||
bgl_named_params<int, buffer_param_t> params(0); // bogus empty param
|
||||
return kolmogorov_max_flow(g, src, sink, params);
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_KOLMOGOROV_MAX_FLOW_HPP
|
||||
|
@ -9,15 +9,13 @@
|
||||
|
||||
/*
|
||||
Reads maximal flow problem in extended DIMACS format.
|
||||
|
||||
Reads from stdin.
|
||||
|
||||
This works, but could use some polishing.
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
#include <vector>
|
||||
#include <istream>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace boost {
|
||||
@ -27,7 +25,8 @@ int read_dimacs_max_flow(Graph& g,
|
||||
CapacityMap capacity,
|
||||
ReverseEdgeMap reverse_edge,
|
||||
typename graph_traits<Graph>::vertex_descriptor& src,
|
||||
typename graph_traits<Graph>::vertex_descriptor& sink)
|
||||
typename graph_traits<Graph>::vertex_descriptor& sink,
|
||||
std::istream& in=std::cin)
|
||||
{
|
||||
// const int MAXLINE = 100; /* max line length in the input file */
|
||||
const int ARC_FIELDS = 3; /* no of fields in arc line */
|
||||
@ -114,7 +113,7 @@ int read_dimacs_max_flow(Graph& g,
|
||||
- does service functions
|
||||
*/
|
||||
|
||||
while (std::getline(std::cin, in_line)) {
|
||||
while (std::getline(in, in_line)) {
|
||||
++no_lines;
|
||||
|
||||
switch (in_line[0]) {
|
||||
|
72
include/boost/graph/write_dimacs.hpp
Normal file
72
include/boost/graph/write_dimacs.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/*
|
||||
Writes maximal flow problem in extended DIMACS format to an OutputIterator
|
||||
Vertex indices are read from an IndexMap and shiftet by 1.
|
||||
so their new range is [1..num_vertices(g)]
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <class Graph, class CapacityMap, class IndexMap>
|
||||
void write_dimacs_max_flow(const Graph& g,
|
||||
CapacityMap capacity,
|
||||
IndexMap idx,
|
||||
typename graph_traits<Graph>::vertex_descriptor src,
|
||||
typename graph_traits<Graph>::vertex_descriptor sink,
|
||||
std::ostream& out)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
|
||||
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
|
||||
|
||||
out << "c DIMACS max-flow file generated from boost::write_dimacs_max_flow" << std::endl;
|
||||
out << "p max " << num_vertices(g) << " " << num_edges(g) << std::endl; //print problem description "max" and number of verts and edges
|
||||
out << "n " << get(idx, src) + 1 << " s" << std::endl;; //say which one is source
|
||||
out << "n " << get(idx, sink) + 1 << " t" << std::endl; //say which one is sink
|
||||
|
||||
//output the edges
|
||||
edge_iterator ei, e_end;
|
||||
for(tie(ei,e_end) = edges(g); ei!=e_end; ++ei){
|
||||
out << "a " << idx[ source(*ei, g) ] + 1 << " " << idx[ target(*ei, g) ] + 1 << " " << get(capacity,*ei) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace boost
|
@ -93,6 +93,9 @@ test-suite graph_test :
|
||||
|
||||
[ run matching_test.cpp ]
|
||||
|
||||
[ run max_flow_test.cpp ]
|
||||
|
||||
[ run kolmogorov_max_flow_test.cpp ]
|
||||
;
|
||||
|
||||
# Run SDB tests only when -sSDB= is set.
|
||||
|
434
test/kolmogorov_max_flow_test.cpp
Normal file
434
test/kolmogorov_max_flow_test.cpp
Normal file
@ -0,0 +1,434 @@
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/graph/kolmogorov_max_flow.hpp>
|
||||
//boost utilities we use
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/adjacency_matrix.hpp>
|
||||
#include <boost/graph/random.hpp>
|
||||
#include <boost/property_map.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
template <typename Graph, typename CapacityMap, typename ReverseEdgeMap>
|
||||
std::pair< typename graph_traits<Graph>::vertex_descriptor,typename graph_traits<Graph>::vertex_descriptor>
|
||||
fill_random_max_flow_graph(Graph& g, CapacityMap cap, ReverseEdgeMap rev, typename graph_traits<Graph>::vertices_size_type n_verts,
|
||||
typename graph_traits<Graph>::edges_size_type n_edges, std::size_t seed)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
const int cap_low = 1;
|
||||
const int cap_high = 1000;
|
||||
|
||||
//init random numer generator
|
||||
minstd_rand gen(seed);
|
||||
//generate graph
|
||||
generate_random_graph(g, n_verts, n_edges, gen);
|
||||
|
||||
//init an uniform distribution int generator
|
||||
typedef variate_generator<minstd_rand, uniform_int<int> > tIntGen;
|
||||
tIntGen int_gen(gen, uniform_int<int>(cap_low, cap_high));
|
||||
//randomize edge-capacities
|
||||
//randomize_property<edge_capacity, Graph, tIntGen> (g,int_gen); //we cannot use this, as we have no idea how properties are stored, right?
|
||||
typename graph_traits<Graph>::edge_iterator ei, e_end;
|
||||
for(tie(ei,e_end) = edges(g); ei != e_end; ++ei)
|
||||
cap[*ei] = int_gen();
|
||||
|
||||
//get source and sink node
|
||||
vertex_descriptor s = random_vertex(g, gen);
|
||||
vertex_descriptor t = graph_traits<Graph>::null_vertex();
|
||||
while(t == graph_traits<Graph>::null_vertex() || t == s)
|
||||
t = random_vertex(g, gen);
|
||||
|
||||
//add reverse edges (ugly... how to do better?!)
|
||||
std::list<edge_descriptor> edges_copy;
|
||||
tie(ei, e_end) = edges(g);
|
||||
std::copy(ei, e_end, std::back_insert_iterator< std::list<edge_descriptor> >(edges_copy));
|
||||
while(!edges_copy.empty()){
|
||||
edge_descriptor old_edge = edges_copy.front();
|
||||
edges_copy.pop_front();
|
||||
vertex_descriptor source_vertex = target(old_edge, g);
|
||||
vertex_descriptor target_vertex = source(old_edge, g);
|
||||
bool inserted;
|
||||
edge_descriptor new_edge;
|
||||
tie(new_edge,inserted) = add_edge(source_vertex, target_vertex, g);
|
||||
assert(inserted);
|
||||
rev[old_edge] = new_edge;
|
||||
rev[new_edge] = old_edge ;
|
||||
cap[new_edge] = 0;
|
||||
}
|
||||
return std::make_pair(s,t);
|
||||
}
|
||||
|
||||
long test_adjacency_list_vecS(int n_verts, int n_edges, std::size_t seed){
|
||||
typedef adjacency_list_traits<vecS, vecS, directedS> tVectorTraits;
|
||||
typedef adjacency_list<vecS, vecS, directedS,
|
||||
property<vertex_index_t, long,
|
||||
property<vertex_predecessor_t, tVectorTraits::edge_descriptor,
|
||||
property<vertex_color_t, boost::default_color_type,
|
||||
property<vertex_distance_t, long> > > >,
|
||||
property<edge_capacity_t, long,
|
||||
property<edge_residual_capacity_t, long,
|
||||
property<edge_reverse_t, tVectorTraits::edge_descriptor > > > > tVectorGraph;
|
||||
|
||||
tVectorGraph g;
|
||||
|
||||
graph_traits<tVectorGraph>::vertex_descriptor src,sink;
|
||||
tie(src,sink) = fill_random_max_flow_graph(g, get(edge_capacity,g), get(edge_reverse, g), n_verts, n_edges, seed);
|
||||
|
||||
return kolmogorov_max_flow(g, get(edge_capacity, g),
|
||||
get(edge_residual_capacity, g),
|
||||
get(edge_reverse, g),
|
||||
get(vertex_predecessor, g),
|
||||
get(vertex_color, g),
|
||||
get(vertex_distance, g),
|
||||
get(vertex_index, g),
|
||||
src, sink);
|
||||
}
|
||||
|
||||
long test_adjacency_list_listS(int n_verts, int n_edges, std::size_t seed){
|
||||
typedef adjacency_list_traits<listS, listS, directedS> tListTraits;
|
||||
typedef adjacency_list<listS, listS, directedS,
|
||||
property<vertex_index_t, long,
|
||||
property<vertex_predecessor_t, tListTraits::edge_descriptor,
|
||||
property<vertex_color_t, boost::default_color_type,
|
||||
property<vertex_distance_t, long> > > >,
|
||||
property<edge_capacity_t, long,
|
||||
property<edge_residual_capacity_t, long,
|
||||
property<edge_reverse_t, tListTraits::edge_descriptor > > > > tListGraph;
|
||||
|
||||
tListGraph g;
|
||||
|
||||
graph_traits<tListGraph>::vertex_descriptor src,sink;
|
||||
tie(src,sink) = fill_random_max_flow_graph(g, get(edge_capacity,g), get(edge_reverse, g), n_verts, n_edges, seed);
|
||||
|
||||
//initialize vertex indices
|
||||
graph_traits<tListGraph>::vertex_iterator vi,v_end;
|
||||
graph_traits<tListGraph>::vertices_size_type index = 0;
|
||||
for(tie(vi, v_end) = vertices(g); vi != v_end; ++vi){
|
||||
put(vertex_index, g, *vi, index++);
|
||||
}
|
||||
return kolmogorov_max_flow(g, get(edge_capacity, g),
|
||||
get(edge_residual_capacity, g),
|
||||
get(edge_reverse, g),
|
||||
get(vertex_predecessor, g),
|
||||
get(vertex_color, g),
|
||||
get(vertex_distance, g),
|
||||
get(vertex_index, g),
|
||||
src, sink);
|
||||
}
|
||||
|
||||
template<typename EdgeDescriptor>
|
||||
struct Node{
|
||||
boost::default_color_type vertex_color;
|
||||
long vertex_distance;
|
||||
EdgeDescriptor vertex_predecessor;
|
||||
};
|
||||
|
||||
template<typename EdgeDescriptor>
|
||||
struct Link{
|
||||
long edge_capacity;
|
||||
long edge_residual_capacity;
|
||||
EdgeDescriptor edge_reverse;
|
||||
};
|
||||
|
||||
long test_bundled_properties(int n_verts, int n_edges, std::size_t seed){
|
||||
typedef adjacency_list_traits<vecS, vecS, directedS> tTraits;
|
||||
typedef Node<tTraits::edge_descriptor> tVertex;
|
||||
typedef Link<tTraits::edge_descriptor> tEdge;
|
||||
typedef adjacency_list<vecS, vecS, directedS, tVertex, tEdge> tBundleGraph;
|
||||
|
||||
tBundleGraph g;
|
||||
|
||||
graph_traits<tBundleGraph>::vertex_descriptor src,sink;
|
||||
tie(src,sink) = fill_random_max_flow_graph(g, get(&tEdge::edge_capacity,g), get(&tEdge::edge_reverse, g), n_verts, n_edges, seed);
|
||||
return kolmogorov_max_flow(g, get(&tEdge::edge_capacity, g),
|
||||
get(&tEdge::edge_residual_capacity, g),
|
||||
get(&tEdge::edge_reverse, g),
|
||||
get(&tVertex::vertex_predecessor, g),
|
||||
get(&tVertex::vertex_color, g),
|
||||
get(&tVertex::vertex_distance, g),
|
||||
get(vertex_index, g),
|
||||
src, sink);
|
||||
}
|
||||
|
||||
long test_overloads(int n_verts, int n_edges, std::size_t seed){
|
||||
typedef adjacency_list_traits<vecS, vecS, directedS> tTraits;
|
||||
typedef property <edge_capacity_t, long,
|
||||
property<edge_residual_capacity_t, long,
|
||||
property<edge_reverse_t, tTraits::edge_descriptor> > >tEdgeProperty;
|
||||
typedef adjacency_list<vecS, vecS, directedS, no_property, tEdgeProperty> tGraph;
|
||||
|
||||
tGraph g;
|
||||
|
||||
graph_traits<tGraph>::vertex_descriptor src,sink;
|
||||
tie(src,sink) = fill_random_max_flow_graph(g, get(edge_capacity,g), get(edge_reverse, g), n_verts, n_edges, seed);
|
||||
|
||||
std::vector<graph_traits<tGraph>::edge_descriptor> predecessor_vec(n_verts);
|
||||
std::vector<default_color_type> color_vec(n_verts);
|
||||
std::vector<graph_traits<tGraph>::vertices_size_type> distance_vec(n_verts);
|
||||
|
||||
long flow_overload_1 = kolmogorov_max_flow(g, get(edge_capacity,g), get(edge_residual_capacity,g), get(edge_reverse,g), get(vertex_index,g), src, sink);
|
||||
|
||||
long flow_overload_2 = kolmogorov_max_flow(g, get(edge_capacity,g), get(edge_residual_capacity,g), get(edge_reverse,g),
|
||||
&(color_vec[0]), get(vertex_index,g), src, sink);
|
||||
|
||||
BOOST_CHECK(flow_overload_1 == flow_overload_2);
|
||||
return flow_overload_1;
|
||||
}
|
||||
|
||||
template <class Graph, class EdgeCapacityMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class PredecessorMap, class ColorMap,
|
||||
class DistanceMap, class IndexMap>
|
||||
class kolmogorov_test:public detail::kolmogorov<Graph,EdgeCapacityMap,ResidualCapacityEdgeMap,ReverseEdgeMap,PredecessorMap,ColorMap,DistanceMap,IndexMap>
|
||||
{
|
||||
|
||||
typedef typename graph_traits<Graph>::edge_descriptor tEdge;
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor tVertex;
|
||||
typedef typename property_traits< typename property_map<Graph, edge_capacity_t>::const_type>::value_type tEdgeVal;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator tVertexIterator;
|
||||
typedef typename graph_traits<Graph>::out_edge_iterator tOutEdgeIterator;
|
||||
typedef typename property_traits<ColorMap>::value_type tColorValue;
|
||||
typedef color_traits<tColorValue> tColorTraits;
|
||||
typedef typename property_traits<DistanceMap>::value_type tDistanceVal;
|
||||
typedef typename detail::kolmogorov<Graph,EdgeCapacityMap,ResidualCapacityEdgeMap,ReverseEdgeMap,PredecessorMap,ColorMap,DistanceMap,IndexMap> tSuper;
|
||||
public:
|
||||
kolmogorov_test(Graph& g, typename graph_traits<Graph>::vertex_descriptor src, typename graph_traits<Graph>::vertex_descriptor sink):
|
||||
detail::kolmogorov<Graph,EdgeCapacityMap,ResidualCapacityEdgeMap,ReverseEdgeMap,PredecessorMap,ColorMap,DistanceMap,IndexMap>
|
||||
(g, get(edge_capacity,g), get(edge_residual_capacity,g), get(edge_reverse, g), get(vertex_predecessor, g), get(vertex_color, g),
|
||||
get(vertex_distance, g), get(vertex_index, g), src, sink){
|
||||
}
|
||||
|
||||
void invariant_four(tVertex v) const{
|
||||
//passive nodes in S or T
|
||||
if(v == tSuper::m_source || v == tSuper::m_sink)
|
||||
return;
|
||||
typename std::list<tVertex>::const_iterator it = find(tSuper::m_orphans.begin(), tSuper::m_orphans.end(), v);
|
||||
// a node is active, if its in the active_list AND (is has_a_parent, or its already in the orphans_list or its the sink, or its the source)
|
||||
bool is_active = (tSuper::m_in_active_list_map[v] && (has_parent(v) || it != tSuper::m_orphans.end() ));
|
||||
if(get_tree(v) != tColorTraits::gray() && !is_active){
|
||||
typename graph_traits<Graph>::out_edge_iterator ei,e_end;
|
||||
for(tie(ei, e_end) = out_edges(v, tSuper::m_g); ei != e_end; ++ei){
|
||||
const tVertex& other_node = target(*ei, tSuper::m_g);
|
||||
if(get_tree(other_node) != get_tree(v)){
|
||||
if(get_tree(v) == tColorTraits::white())
|
||||
BOOST_CHECK(tSuper::m_res_cap_map[*ei] == 0);
|
||||
else
|
||||
BOOST_CHECK(tSuper::m_res_cap_map[tSuper::m_rev_edge_map[*ei]] == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void invariant_five(const tVertex& v) const{
|
||||
BOOST_CHECK(get_tree(v) != tColorTraits::gray() || tSuper::m_time_map[v] <= tSuper::m_time);
|
||||
}
|
||||
|
||||
void invariant_six(const tVertex& v) const{
|
||||
if(get_tree(v) == tColorTraits::gray() || tSuper::m_time_map[v] != tSuper::m_time)
|
||||
return;
|
||||
else{
|
||||
tVertex current_node = v;
|
||||
tDistanceVal distance = 0;
|
||||
tColorValue color = get_tree(v);
|
||||
tVertex terminal = (color == tColorTraits::white()) ? tSuper::m_source : tSuper::m_sink;
|
||||
while(current_node != terminal){
|
||||
BOOST_CHECK(tSuper::has_parent(current_node));
|
||||
tEdge e = get_edge_to_parent(current_node);
|
||||
++distance;
|
||||
current_node = (color == tColorTraits::white())? source(e, tSuper::m_g) : target(e, tSuper::m_g);
|
||||
if(distance > tSuper::m_dist_map[v])
|
||||
break;
|
||||
}
|
||||
BOOST_CHECK(distance == tSuper::m_dist_map[v]);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant_seven(const tVertex& v) const{
|
||||
if(get_tree(v) == tColorTraits::gray())
|
||||
return;
|
||||
else{
|
||||
tColorValue color = get_tree(v);
|
||||
long time = tSuper::m_time_map[v];
|
||||
tVertex current_node = v;
|
||||
while(tSuper::has_parent(current_node)){
|
||||
tEdge e = get_edge_to_parent(current_node);
|
||||
current_node = (color == tColorTraits::white()) ? source(e, tSuper::m_g) : target(e, tSuper::m_g);
|
||||
BOOST_CHECK(tSuper::m_time_map[current_node] >= time);
|
||||
}
|
||||
}
|
||||
}//invariant_seven
|
||||
|
||||
void invariant_eight(const tVertex& v) const{
|
||||
if(get_tree(v) == tColorTraits::gray())
|
||||
return;
|
||||
else{
|
||||
tColorValue color = get_tree(v);
|
||||
long time = tSuper::m_time_map[v];
|
||||
tDistanceVal distance = tSuper::m_dist_map[v];
|
||||
tVertex current_node = v;
|
||||
while(tSuper::has_parent(current_node)){
|
||||
tEdge e = get_edge_to_parent(current_node);
|
||||
current_node = (color == tColorTraits::white()) ? source(e, tSuper::m_g) : target(e, tSuper::m_g);
|
||||
if(tSuper::m_time_map[current_node] == time)
|
||||
BOOST_CHECK(tSuper::m_dist_map[current_node] < distance);
|
||||
}
|
||||
}
|
||||
}//invariant_eight
|
||||
|
||||
void check_invariants(){
|
||||
tVertexIterator vi, v_end;
|
||||
for(tie(vi, v_end) = vertices(tSuper::m_g); vi != v_end; ++vi){
|
||||
invariant_four(*vi);
|
||||
invariant_five(*vi);
|
||||
invariant_six(*vi);
|
||||
invariant_seven(*vi);
|
||||
invariant_eight(*vi);
|
||||
}
|
||||
}
|
||||
|
||||
tEdgeVal test(){
|
||||
this->add_active_node(this->m_sink);
|
||||
this->augment_direct_paths();
|
||||
check_invariants();
|
||||
//start the main-loop
|
||||
while(true){
|
||||
bool path_found;
|
||||
tEdge connecting_edge;
|
||||
tie(connecting_edge, path_found) = this->grow(); //find a path from source to sink
|
||||
if(!path_found){
|
||||
//we're finished, no more paths were found
|
||||
break;
|
||||
}
|
||||
check_invariants();
|
||||
this->m_time++;
|
||||
this->augment(connecting_edge); //augment that path
|
||||
check_invariants();
|
||||
this->adopt(); //rebuild search tree structure
|
||||
check_invariants();
|
||||
}
|
||||
|
||||
//check if flow is the sum of outgoing edges of src
|
||||
tOutEdgeIterator ei, e_end;
|
||||
tEdgeVal src_sum = 0;
|
||||
for(tie(ei, e_end) = out_edges(this->m_source, this->m_g); ei != e_end; ++ei){
|
||||
src_sum += this->m_cap_map[*ei] - this->m_res_cap_map[*ei];
|
||||
}
|
||||
BOOST_CHECK(this->m_flow == src_sum);
|
||||
//check if flow is the sum of ingoing edges of sink
|
||||
tEdgeVal sink_sum = 0;
|
||||
for(tie(ei, e_end) = out_edges(this->m_sink, this->m_g); ei != e_end; ++ei){
|
||||
tEdge in_edge = this->m_rev_edge_map[*ei];
|
||||
sink_sum += this->m_cap_map[in_edge] - this->m_res_cap_map[in_edge];
|
||||
}
|
||||
BOOST_CHECK(this->m_flow == sink_sum);
|
||||
return this->m_flow;
|
||||
}
|
||||
};
|
||||
|
||||
long test_algorithms_invariant(int n_verts, int n_edges, std::size_t seed)
|
||||
{
|
||||
typedef adjacency_list_traits<vecS, vecS, directedS> tVectorTraits;
|
||||
typedef adjacency_list<vecS, vecS, directedS,
|
||||
property<vertex_index_t, long,
|
||||
property<vertex_predecessor_t, tVectorTraits::edge_descriptor,
|
||||
property<vertex_color_t, default_color_type,
|
||||
property<vertex_distance_t, long> > > >,
|
||||
property<edge_capacity_t, long,
|
||||
property<edge_residual_capacity_t, long,
|
||||
property<edge_reverse_t, tVectorTraits::edge_descriptor > > > > tVectorGraph;
|
||||
|
||||
tVectorGraph g;
|
||||
|
||||
graph_traits<tVectorGraph>::vertex_descriptor src, sink;
|
||||
tie(src,sink) = fill_random_max_flow_graph(g, get(edge_capacity,g), get(edge_reverse, g), n_verts, n_edges, seed);
|
||||
|
||||
typedef property_map<tVectorGraph, edge_capacity_t>::type tEdgeCapMap;
|
||||
typedef property_map<tVectorGraph, edge_residual_capacity_t>::type tEdgeResCapMap;
|
||||
typedef property_map<tVectorGraph, edge_reverse_t>::type tRevEdgeMap;
|
||||
typedef property_map<tVectorGraph, vertex_predecessor_t>::type tVertexPredMap;
|
||||
typedef property_map<tVectorGraph, vertex_color_t>::type tVertexColorMap;
|
||||
typedef property_map<tVectorGraph, vertex_distance_t>::type tDistanceMap;
|
||||
typedef property_map<tVectorGraph, vertex_index_t>::type tIndexMap;
|
||||
typedef kolmogorov_test<tVectorGraph, tEdgeCapMap, tEdgeResCapMap, tRevEdgeMap, tVertexPredMap, tVertexColorMap, tDistanceMap, tIndexMap> tKolmo;
|
||||
tKolmo instance(g, src, sink);
|
||||
return instance.test();
|
||||
}
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
int n_verts = 10;
|
||||
int n_edges = 500;
|
||||
std::size_t seed = 1;
|
||||
|
||||
if (argc > 1) n_verts = lexical_cast<int>(argv[1]);
|
||||
if (argc > 2) n_edges = lexical_cast<int>(argv[2]);
|
||||
if (argc > 3) seed = lexical_cast<std::size_t>(argv[3]);
|
||||
|
||||
//we need at least 2 vertices to create src and sink in random graphs
|
||||
//this case is also caught in kolmogorov_max_flow
|
||||
if (n_verts<2)
|
||||
n_verts = 2;
|
||||
|
||||
/*
|
||||
* below are checks for different calls to kolmogorov_max_flow and different graph-types
|
||||
*/
|
||||
//checks support of vecS storage
|
||||
long flow_vecS = test_adjacency_list_vecS(n_verts, n_edges, seed);
|
||||
std::cout << "vecS flow: " << flow_vecS << std::endl;
|
||||
//checks support of listS storage (especially problems with vertex indices)
|
||||
long flow_listS = test_adjacency_list_listS(n_verts, n_edges, seed);
|
||||
std::cout << "listS flow: " << flow_listS << std::endl;
|
||||
BOOST_CHECK(flow_vecS == flow_listS);
|
||||
//checks bundled properties
|
||||
long flow_bundles = test_bundled_properties(n_verts, n_edges, seed);
|
||||
std::cout << "bundles flow: " << flow_bundles << std::endl;
|
||||
BOOST_CHECK(flow_listS == flow_bundles);
|
||||
//checks overloads
|
||||
long flow_overloads = test_overloads(n_verts, n_edges, seed);
|
||||
std::cout << "overloads flow: " << flow_overloads << std::endl;
|
||||
BOOST_CHECK(flow_bundles == flow_overloads);
|
||||
/*
|
||||
* excessive test version where kolmogorov's algorithm invariants are checked
|
||||
*/
|
||||
long flow_invariants = test_algorithms_invariant(n_verts, n_edges, seed);
|
||||
std::cout << "invariants flow: " << flow_invariants << std::endl;
|
||||
BOOST_CHECK(flow_overloads == flow_invariants);
|
||||
return 0;
|
||||
}
|
136
test/max_flow_test.cpp
Normal file
136
test/max_flow_test.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2006, Stephan Diederich
|
||||
//
|
||||
// This code may be used under either of the following two licences:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/test/minimal.hpp>
|
||||
//three max_flows we test here
|
||||
#include <boost/graph/kolmogorov_max_flow.hpp>
|
||||
#include <boost/graph/push_relabel_max_flow.hpp>
|
||||
#include <boost/graph/edmunds_karp_max_flow.hpp>
|
||||
//boost utilities we use
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/random.hpp>
|
||||
#include <boost/property_map.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
/***************
|
||||
* test which compares results of the three different max_flow implementations
|
||||
* command line parameters:
|
||||
* number_of_vertices: defaults to 100
|
||||
* number_of_edges: defaults to 1000
|
||||
* seeed: defaults to 1
|
||||
***************/
|
||||
|
||||
using namespace boost;
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
typedef adjacency_list_traits < vecS, vecS, directedS > Traits;
|
||||
typedef adjacency_list < vecS, vecS, directedS,
|
||||
property < vertex_index_t, long,
|
||||
property < vertex_color_t, boost::default_color_type,
|
||||
property < vertex_distance_t, long,
|
||||
property < vertex_predecessor_t, Traits::edge_descriptor > > > >,
|
||||
property < edge_capacity_t, long,
|
||||
property < edge_residual_capacity_t, long,
|
||||
property < edge_reverse_t, Traits::edge_descriptor > > > > Graph;
|
||||
|
||||
typedef graph_traits<Graph>::edge_descriptor tEdge;
|
||||
typedef graph_traits<Graph>::vertex_descriptor tVertex;
|
||||
|
||||
graph_traits<Graph>::vertices_size_type n_verts = 100;
|
||||
graph_traits<Graph>::edges_size_type n_edges = 1000;
|
||||
std::size_t seed = 1;
|
||||
|
||||
if (argc > 1) n_verts = lexical_cast<std::size_t>(argv[1]);
|
||||
if (argc > 2) n_edges = lexical_cast<std::size_t>(argv[2]);
|
||||
if (argc > 3) seed = lexical_cast<std::size_t>(argv[3]);
|
||||
|
||||
Graph g;
|
||||
const int cap_low = 1;
|
||||
const int cap_high = 1000;
|
||||
|
||||
//init random numer generator
|
||||
minstd_rand gen(seed);
|
||||
//generate graph
|
||||
generate_random_graph(g, n_verts, n_edges, gen);
|
||||
|
||||
//init an uniform distribution int generator
|
||||
typedef variate_generator<minstd_rand, uniform_int<int> > tIntGen;
|
||||
tIntGen int_gen(gen, uniform_int<int>(cap_low, cap_high));
|
||||
//init edge-capacities
|
||||
randomize_property<edge_capacity_t, Graph, tIntGen> (g,int_gen);
|
||||
|
||||
//get source and sink node
|
||||
tVertex source_vertex = random_vertex(g, gen);
|
||||
tVertex sink_vertex = graph_traits<Graph>::null_vertex();
|
||||
while(sink_vertex == graph_traits<Graph>::null_vertex() || sink_vertex == source_vertex)
|
||||
sink_vertex = random_vertex(g, gen);
|
||||
|
||||
//add reverse edges (ugly... how to do better?!)
|
||||
property_map < Graph, edge_reverse_t >::type rev = get(edge_reverse, g);
|
||||
property_map < Graph, edge_capacity_t >::type cap = get(edge_capacity, g);
|
||||
std::list<tEdge> edges_copy;
|
||||
graph_traits<Graph>::edge_iterator ei, e_end;
|
||||
tie(ei, e_end) = edges(g);
|
||||
std::copy(ei, e_end, std::back_insert_iterator< std::list<tEdge> >(edges_copy));
|
||||
while( ! edges_copy.empty()){
|
||||
tEdge old_edge=edges_copy.front();
|
||||
edges_copy.pop_front();
|
||||
tVertex source_vertex = target(old_edge, g);
|
||||
tVertex target_vertex = source(old_edge, g);
|
||||
bool inserted;
|
||||
tEdge new_edge;
|
||||
tie(new_edge,inserted) = add_edge(source_vertex, target_vertex, g);
|
||||
assert(inserted);
|
||||
rev[old_edge] = new_edge;
|
||||
rev[new_edge] = old_edge ;
|
||||
cap[new_edge] = 0;
|
||||
}
|
||||
|
||||
typedef property_traits< property_map<Graph, edge_capacity_t>::const_type>::value_type tEdgeVal;
|
||||
|
||||
tEdgeVal kolmo = kolmogorov_max_flow(g,source_vertex,sink_vertex);
|
||||
tEdgeVal push_relabel = push_relabel_max_flow(g,source_vertex,sink_vertex);
|
||||
tEdgeVal edmunds_karp = edmunds_karp_max_flow(g,source_vertex,sink_vertex);
|
||||
|
||||
BOOST_REQUIRE( kolmo == push_relabel );
|
||||
BOOST_REQUIRE( push_relabel == edmunds_karp );
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user