Commit 2182538b authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Add check for directed graphs in flow module, and rename kolmogorov_max_flow

This adds a check for directed graphs in most functions of the flow
module, and renames the kolmogorov_max_flow to
koybov_kolmogorov_max_flow.

This also optimizes the graph augmentation in
koybov_kolmogorov_max_flow, where reversed edges are detected and used
if they exist.
parent 8af15810
......@@ -24,11 +24,12 @@ using namespace boost;
template <class Graph, class AugmentedMap, class CapacityMap,
class ReversedMap, class ResidualMap>
void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity,
ReversedMap rmap, ResidualMap res)
ReversedMap rmap, ResidualMap res,
bool detect_reversed = false)
{
typename graph_traits<Graph>::edge_iterator e, e_end;
for (tie(e,e_end) = edges(g); e != e_end; ++e)
augmented[*e] = false;
augmented[*e] = 0;
typename graph_traits<Graph>::vertex_iterator v, v_end;
vector<typename graph_traits<Graph>::edge_descriptor> e_list;
......@@ -39,7 +40,27 @@ void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity,
typename graph_traits<Graph>::out_edge_iterator e, e_end;
for (tie(e, e_end) = out_edges(*v, g); e != e_end; ++e)
{
if (!augmented[*e])
if (detect_reversed && augmented[*e] != 0)
{
typename graph_traits<Graph>::out_edge_iterator e2, e2_end;
for (tie(e2, e2_end) = out_edges(target(*e, g), g);
e2 != e2_end; ++e2)
{
if (augmented[*e2] != 0)
continue;
if (target(*e2, g) == *v)
{
augmented[*e] = 2;
augmented[*e2] = 2;
rmap[*e] = *e2;
rmap[*e2] = *e;
break;
}
}
}
if (augmented[*e] == 0)
e_list.push_back(*e);
}
......@@ -47,7 +68,7 @@ void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity,
{
typename graph_traits<Graph>::edge_descriptor ae;
ae = add_edge(target(e_list[i],g), source(e_list[i],g), g).first;
augmented[ae] = true;
augmented[ae] = 1;
capacity[ae] = 0;
rmap[e_list[i]] = ae;
rmap[ae] = e_list[i];
......@@ -67,12 +88,12 @@ void deaugment_graph(Graph& g, AugmentedMap augmented)
typename graph_traits<Graph>::out_edge_iterator e, e_end;
for (tie(e, e_end) = out_edges(*v, g); e != e_end; ++e)
{
if (augmented[*e])
if (augmented[*e] == 1)
e_list.push_back(*e);
}
for (size_t i = 0; i < e_list.size(); ++i)
remove_edge(e_list[i],g);
remove_edge(e_list[i], g);
}
}
......
......@@ -41,12 +41,15 @@ struct get_edmonds_karp_max_flow
augmented(edge_index, max_e);
unchecked_vector_property_map<edge_t,EdgeIndex>
reverse_map(edge_index, max_e);
augment_graph(g, augmented.get_checked(), cm, reverse_map.get_checked(),
res);
boost::edmonds_karp_max_flow(g._g, vertex(src, g), vertex(sink, g),
capacity_map(get_unchecked(cm)).
reverse_edge_map(reverse_map).
residual_capacity_map(res.get_unchecked()));
deaugment_graph(g, augmented.get_checked());
}
};
......
......@@ -44,13 +44,19 @@ min(const T1& v1, const T2& v2)
}
}
#include <boost/graph/kolmogorov_max_flow.hpp>
#include <boost/bind.hpp>
using namespace graph_tool;
using namespace boost;
#if (BOOST_VERSION >= 104400)
# include <boost/graph/boykov_kolmogorov_max_flow.hpp>
# define KOLMOGOROV_MAX_FLOW boost::boykov_kolmogorov_max_flow
#else
# include <boost/graph/kolmogorov_max_flow.hpp>
# define KOLMOGOROV_MAX_FLOW boost::kolmogorov_max_flow
#endif
struct get_kolmogorov_max_flow
{
template <class Graph, class EdgeIndex, class VertexIndex,
......@@ -72,18 +78,21 @@ struct get_kolmogorov_max_flow
dist_map(vertex_index, num_vertices(g));
augment_graph(g, augmented.get_checked(), cm,
reverse_map.get_checked(), res);
boost::kolmogorov_max_flow(g._g, get_unchecked(cm),
res.get_unchecked(), reverse_map, pred_map,
color_map, dist_map, vertex_index,
vertex(src, g), vertex(sink, g));
reverse_map.get_checked(), res, true);
KOLMOGOROV_MAX_FLOW(g._g, get_unchecked(cm),
res.get_unchecked(), reverse_map, pred_map,
color_map, dist_map, vertex_index,
vertex(src, g), vertex(sink, g));
deaugment_graph(g, augmented.get_checked());
}
};
void kolmogorov_max_flow(GraphInterface& gi, size_t src, size_t sink,
boost::any capacity, boost::any res)
boost::any capacity, boost::any res)
{
run_action<graph_tool::detail::always_directed, mpl::true_>()
(gi, bind<void>(get_kolmogorov_max_flow(),
......
......@@ -61,17 +61,20 @@ struct get_push_relabel_max_flow
size_t sink, CapacityMap cm, ResidualMap res) const
{
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
unchecked_vector_property_map<bool,EdgeIndex>
augmented(edge_index, max_e);
checked_vector_property_map<bool,EdgeIndex>
augmented(edge_index);
unchecked_vector_property_map<edge_t,EdgeIndex>
reverse_map(edge_index, max_e);
augment_graph(g, augmented.get_checked(), cm,
augment_graph(g, augmented, cm,
reverse_map.get_checked(), res);
boost::push_relabel_max_flow(g._g, vertex(src, g), vertex(sink, g),
capacity_map(get_unchecked(cm)).
reverse_edge_map(reverse_map).
residual_capacity_map(res.get_unchecked()));
deaugment_graph(g, augmented.get_checked());
deaugment_graph(g, augmented);
}
};
......
......@@ -30,7 +30,7 @@ Summary
edmonds_karp_max_flow
push_relabel_max_flow
kolmogorov_max_flow
boykov_kolmogorov_max_flow
max_cardinality_matching
Contents
......@@ -42,12 +42,12 @@ dl_import("import libgraph_tool_flow")
from .. core import _prop, _check_prop_scalar, _check_prop_writable
__all__ = ["edmonds_karp_max_flow", "push_relabel_max_flow",
"kolmogorov_max_flow", "max_cardinality_matching"]
"boykov_kolmogorov_max_flow", "max_cardinality_matching"]
def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
r"""
Calculate maximum flow on the graph with Edmonds-Karp algorithm.
Calculate maximum flow on the graph with the Edmonds-Karp algorithm.
Parameters
----------
......@@ -75,8 +75,8 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
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 push_relabel_max_flow() or the kolmogorov_max_flow()
algorithm.
is not as good as the push_relabel_max_flow() or the
boykov_kolmogorov_max_flow() algorithm.
- In the non-integer capacity case, the time complexity is :math:`O(V E^2)`
which is worse than the time complexity of the push-relabel algorithm
......@@ -142,16 +142,19 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
_check_prop_scalar(residual, "residual")
_check_prop_writable(residual, "residual")
if not g.is_directed():
raise ValueError("The graph provided must be directed!")
libgraph_tool_flow.\
edmonds_karp_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity),
_prop("e", g, residual))
edmonds_karp_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity),
_prop("e", g, residual))
return residual
def push_relabel_max_flow(g, source, target, capacity, residual=None):
r"""
Calculate maximum flow on the graph with push-relabel algorithm.
Calculate maximum flow on the graph with the push-relabel algorithm.
Parameters
----------
......@@ -231,15 +234,19 @@ def push_relabel_max_flow(g, source, target, capacity, residual=None):
_check_prop_scalar(residual, "residual")
_check_prop_writable(residual, "residual")
if not g.is_directed():
raise ValueError("The graph provided must be directed!")
libgraph_tool_flow.\
push_relabel_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity),
_prop("e", g, residual))
push_relabel_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity),
_prop("e", g, residual))
return residual
def kolmogorov_max_flow(g, source, target, capacity, residual=None):
r"""Calculate maximum flow on the graph with Kolmogorov algorithm.
def boykov_kolmogorov_max_flow(g, source, target, capacity, residual=None):
r"""Calculate maximum flow on the graph with the Boykov-Kolmogorov algorithm.
Parameters
----------
......@@ -276,51 +283,35 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None):
>>> g = gt.random_graph(100, lambda: (2,2))
>>> c = g.new_edge_property("double")
>>> c.a = random(len(c.a))
>>> res = gt.push_relabel_max_flow(g, g.vertex(0), g.vertex(1), c)
>>> res = gt.boykov_kolmogorov_max_flow(g, g.vertex(0), g.vertex(1), c)
>>> res.a = c.a - res.a # the actual flow
>>> print res.a[0:g.num_edges()]
[ 0.00730949 0.0835572 0. 0. 0. 0. 0.
0.06926091 0.06926091 0. 0.07624771 0. 0.03957485
0.05028544 0.05028544 0. 0. 0. 0.07624771
0.07624771 0. 0.07624771 0. 0. 0.07624771
0. 0. 0. 0. 0. 0.20608185
0.03395359 0. 0. 0.06926091 0. 0. 0.
0. 0. 0. 0. 0.06926091 0.
0.03957485 0. 0. 0. 0. 0.
0.02596227 0.05028544 0.12983414 0. 0. 0.
0.06926091 0. 0.20608185 0. 0. 0. 0.
0.12983414 0. 0. 0. 0.04480769 0. 0.
0. 0.06926091 0. 0. 0.06926091 0.03957485
0.06926091 0.05028544 0. 0.06057324 0. 0.
0.00730949 0. 0. 0. 0. 0.02596227
0. 0.03667285 0. 0. 0. 0. 0.
0. 0. 0.0835572 0. 0. 0. 0.
0.07624771 0.12983414 0.12983414 0. 0. 0.
0.02596227 0. 0. 0. 0. 0.05028544
0. 0. 0. 0.04480769 0. 0. 0.
0. 0.00730949 0. 0. 0.06926091 0.
0.05028544 0. 0. 0.03395359 0. 0. 0.
0. 0. 0. 0.06057324 0. 0. 0.
0.03395359 0. 0. 0. 0. 0.01633184
0. 0. 0. 0. 0.02596227 0. 0.
0. 0. 0. 0. 0.03395359 0. 0.
0. 0. 0. 0.00547774 0. 0.12983414
0.03395359 0. 0. 0. 0. 0.00547774
0. 0. 0. 0. 0. 0.03957485
0.03395359 0. 0.06926091 0. 0. 0. 0.
[ 0.13339096 0.13339096 0. 0. 0. 0. 0.
0. 0.00730949 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0.00730949 0.07624771 0.20608185 0. 0. 0. 0. ]
0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0. 0. 0.20608185 0. 0. 0.
0.07269089 0. 0.00730949 0. 0. 0. 0.
0.13339096 0. 0. 0. 0. 0. 0.
0. 0. 0. 0.07269089 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. ]
References
----------
.. [boost-kolmogorov] http://www.boost.org/libs/graph/doc/kolmogorov_max_flow.html
.. [kolmogorov-graph-2003] Vladimir Kolmogorov, "Graph Based Algorithms for
Scene Reconstruction from Two or More Views", PhD thesis, Cornell
University, September 2003.
University, September 2003.
.. [boykov-experimental-2004] Yuri Boykov and Vladimir Kolmogorov, "An
Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy
Minimization", Vision In IEEE Transactions on Pattern Analysis and
Minimization in Vision", IEEE Transactions on Pattern Analysis and
Machine Intelligence, vol. 26, no. 9, pp. 1124-1137, Sept. 2004.
:doi:`10.1109/TPAMI.2004.60`
"""
_check_prop_scalar(capacity, "capacity")
if residual == None:
......@@ -328,10 +319,13 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None):
_check_prop_scalar(residual, "residual")
_check_prop_writable(residual, "residual")
if not g.is_directed():
raise ValueError("The graph provided must be directed!")
libgraph_tool_flow.\
kolmogorov_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity),
_prop("e", g, residual))
kolmogorov_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity),
_prop("e", g, residual))
return residual
......@@ -385,9 +379,12 @@ def max_cardinality_matching(g, match=None):
_check_prop_scalar(match, "match")
_check_prop_writable(match, "match")
g.stash_filter(directed=True)
g.set_directed(False)
check = libgraph_tool_flow.\
max_cardinality_matching(g._Graph__graph, _prop("e", g, match))
g.pop_filter(directed=True)
try:
g.stash_filter(directed=True)
g.set_directed(False)
check = libgraph_tool_flow.\
max_cardinality_matching(g._Graph__graph, _prop("e", g, match))
finally:
g.pop_filter(directed=True)
return match, check
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment