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; ...@@ -24,11 +24,12 @@ using namespace boost;
template <class Graph, class AugmentedMap, class CapacityMap, template <class Graph, class AugmentedMap, class CapacityMap,
class ReversedMap, class ResidualMap> class ReversedMap, class ResidualMap>
void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity, 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; typename graph_traits<Graph>::edge_iterator e, e_end;
for (tie(e,e_end) = edges(g); e != e_end; ++e) 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; typename graph_traits<Graph>::vertex_iterator v, v_end;
vector<typename graph_traits<Graph>::edge_descriptor> e_list; vector<typename graph_traits<Graph>::edge_descriptor> e_list;
...@@ -39,7 +40,27 @@ void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity, ...@@ -39,7 +40,27 @@ void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity,
typename graph_traits<Graph>::out_edge_iterator e, e_end; typename graph_traits<Graph>::out_edge_iterator e, e_end;
for (tie(e, e_end) = out_edges(*v, g); e != e_end; ++e) 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); e_list.push_back(*e);
} }
...@@ -47,7 +68,7 @@ void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity, ...@@ -47,7 +68,7 @@ void augment_graph(Graph& g, AugmentedMap augmented, CapacityMap capacity,
{ {
typename graph_traits<Graph>::edge_descriptor ae; typename graph_traits<Graph>::edge_descriptor ae;
ae = add_edge(target(e_list[i],g), source(e_list[i],g), g).first; ae = add_edge(target(e_list[i],g), source(e_list[i],g), g).first;
augmented[ae] = true; augmented[ae] = 1;
capacity[ae] = 0; capacity[ae] = 0;
rmap[e_list[i]] = ae; rmap[e_list[i]] = ae;
rmap[ae] = e_list[i]; rmap[ae] = e_list[i];
...@@ -67,12 +88,12 @@ void deaugment_graph(Graph& g, AugmentedMap augmented) ...@@ -67,12 +88,12 @@ void deaugment_graph(Graph& g, AugmentedMap augmented)
typename graph_traits<Graph>::out_edge_iterator e, e_end; typename graph_traits<Graph>::out_edge_iterator e, e_end;
for (tie(e, e_end) = out_edges(*v, g); e != e_end; ++e) 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); e_list.push_back(*e);
} }
for (size_t i = 0; i < e_list.size(); ++i) 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 ...@@ -41,12 +41,15 @@ struct get_edmonds_karp_max_flow
augmented(edge_index, max_e); augmented(edge_index, max_e);
unchecked_vector_property_map<edge_t,EdgeIndex> unchecked_vector_property_map<edge_t,EdgeIndex>
reverse_map(edge_index, max_e); reverse_map(edge_index, max_e);
augment_graph(g, augmented.get_checked(), cm, reverse_map.get_checked(), augment_graph(g, augmented.get_checked(), cm, reverse_map.get_checked(),
res); res);
boost::edmonds_karp_max_flow(g._g, vertex(src, g), vertex(sink, g), boost::edmonds_karp_max_flow(g._g, vertex(src, g), vertex(sink, g),
capacity_map(get_unchecked(cm)). capacity_map(get_unchecked(cm)).
reverse_edge_map(reverse_map). reverse_edge_map(reverse_map).
residual_capacity_map(res.get_unchecked())); residual_capacity_map(res.get_unchecked()));
deaugment_graph(g, augmented.get_checked()); deaugment_graph(g, augmented.get_checked());
} }
}; };
......
...@@ -44,13 +44,19 @@ min(const T1& v1, const T2& v2) ...@@ -44,13 +44,19 @@ min(const T1& v1, const T2& v2)
} }
} }
#include <boost/graph/kolmogorov_max_flow.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
using namespace graph_tool; using namespace graph_tool;
using namespace boost; 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 struct get_kolmogorov_max_flow
{ {
template <class Graph, class EdgeIndex, class VertexIndex, template <class Graph, class EdgeIndex, class VertexIndex,
...@@ -72,12 +78,15 @@ struct get_kolmogorov_max_flow ...@@ -72,12 +78,15 @@ struct get_kolmogorov_max_flow
dist_map(vertex_index, num_vertices(g)); dist_map(vertex_index, num_vertices(g));
augment_graph(g, augmented.get_checked(), cm, augment_graph(g, augmented.get_checked(), cm,
reverse_map.get_checked(), res); reverse_map.get_checked(), res, true);
boost::kolmogorov_max_flow(g._g, get_unchecked(cm),
KOLMOGOROV_MAX_FLOW(g._g, get_unchecked(cm),
res.get_unchecked(), reverse_map, pred_map, res.get_unchecked(), reverse_map, pred_map,
color_map, dist_map, vertex_index, color_map, dist_map, vertex_index,
vertex(src, g), vertex(sink, g)); vertex(src, g), vertex(sink, g));
deaugment_graph(g, augmented.get_checked()); deaugment_graph(g, augmented.get_checked());
} }
}; };
......
...@@ -61,17 +61,20 @@ struct get_push_relabel_max_flow ...@@ -61,17 +61,20 @@ struct get_push_relabel_max_flow
size_t sink, CapacityMap cm, ResidualMap res) const size_t sink, CapacityMap cm, ResidualMap res) const
{ {
typedef typename graph_traits<Graph>::edge_descriptor edge_t; typedef typename graph_traits<Graph>::edge_descriptor edge_t;
unchecked_vector_property_map<bool,EdgeIndex> checked_vector_property_map<bool,EdgeIndex>
augmented(edge_index, max_e); augmented(edge_index);
unchecked_vector_property_map<edge_t,EdgeIndex> unchecked_vector_property_map<edge_t,EdgeIndex>
reverse_map(edge_index, max_e); reverse_map(edge_index, max_e);
augment_graph(g, augmented.get_checked(), cm,
augment_graph(g, augmented, cm,
reverse_map.get_checked(), res); reverse_map.get_checked(), res);
boost::push_relabel_max_flow(g._g, vertex(src, g), vertex(sink, g), boost::push_relabel_max_flow(g._g, vertex(src, g), vertex(sink, g),
capacity_map(get_unchecked(cm)). capacity_map(get_unchecked(cm)).
reverse_edge_map(reverse_map). reverse_edge_map(reverse_map).
residual_capacity_map(res.get_unchecked())); residual_capacity_map(res.get_unchecked()));
deaugment_graph(g, augmented.get_checked());
deaugment_graph(g, augmented);
} }
}; };
......
...@@ -30,7 +30,7 @@ Summary ...@@ -30,7 +30,7 @@ Summary
edmonds_karp_max_flow edmonds_karp_max_flow
push_relabel_max_flow push_relabel_max_flow
kolmogorov_max_flow boykov_kolmogorov_max_flow
max_cardinality_matching max_cardinality_matching
Contents Contents
...@@ -42,12 +42,12 @@ dl_import("import libgraph_tool_flow") ...@@ -42,12 +42,12 @@ dl_import("import libgraph_tool_flow")
from .. core import _prop, _check_prop_scalar, _check_prop_writable from .. core import _prop, _check_prop_scalar, _check_prop_writable
__all__ = ["edmonds_karp_max_flow", "push_relabel_max_flow", __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): def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
r""" r"""
Calculate maximum flow on the graph with Edmonds-Karp algorithm. Calculate maximum flow on the graph with the Edmonds-Karp algorithm.
Parameters Parameters
---------- ----------
...@@ -75,8 +75,8 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None): ...@@ -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 This algorithm provides a very simple and easy to implement solution to the
maximum flow problem. However, there are several reasons why this algorithm 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() is not as good as the push_relabel_max_flow() or the
algorithm. boykov_kolmogorov_max_flow() algorithm.
- In the non-integer capacity case, the time complexity is :math:`O(V E^2)` - 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 which is worse than the time complexity of the push-relabel algorithm
...@@ -142,6 +142,9 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None): ...@@ -142,6 +142,9 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
_check_prop_scalar(residual, "residual") _check_prop_scalar(residual, "residual")
_check_prop_writable(residual, "residual") _check_prop_writable(residual, "residual")
if not g.is_directed():
raise ValueError("The graph provided must be directed!")
libgraph_tool_flow.\ libgraph_tool_flow.\
edmonds_karp_max_flow(g._Graph__graph, int(source), int(target), edmonds_karp_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity), _prop("e", g, capacity),
...@@ -151,7 +154,7 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None): ...@@ -151,7 +154,7 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
def push_relabel_max_flow(g, source, target, capacity, residual=None): def push_relabel_max_flow(g, source, target, capacity, residual=None):
r""" r"""
Calculate maximum flow on the graph with push-relabel algorithm. Calculate maximum flow on the graph with the push-relabel algorithm.
Parameters Parameters
---------- ----------
...@@ -231,15 +234,19 @@ def push_relabel_max_flow(g, source, target, capacity, residual=None): ...@@ -231,15 +234,19 @@ def push_relabel_max_flow(g, source, target, capacity, residual=None):
_check_prop_scalar(residual, "residual") _check_prop_scalar(residual, "residual")
_check_prop_writable(residual, "residual") _check_prop_writable(residual, "residual")
if not g.is_directed():
raise ValueError("The graph provided must be directed!")
libgraph_tool_flow.\ libgraph_tool_flow.\
push_relabel_max_flow(g._Graph__graph, int(source), int(target), push_relabel_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity), _prop("e", g, capacity),
_prop("e", g, residual)) _prop("e", g, residual))
return residual return residual
def kolmogorov_max_flow(g, source, target, capacity, residual=None): def boykov_kolmogorov_max_flow(g, source, target, capacity, residual=None):
r"""Calculate maximum flow on the graph with Kolmogorov algorithm. r"""Calculate maximum flow on the graph with the Boykov-Kolmogorov algorithm.
Parameters Parameters
---------- ----------
...@@ -276,40 +283,23 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None): ...@@ -276,40 +283,23 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None):
>>> g = gt.random_graph(100, lambda: (2,2)) >>> g = gt.random_graph(100, lambda: (2,2))
>>> c = g.new_edge_property("double") >>> c = g.new_edge_property("double")
>>> c.a = random(len(c.a)) >>> 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 >>> res.a = c.a - res.a # the actual flow
>>> print res.a[0:g.num_edges()] >>> print res.a[0:g.num_edges()]
[ 0.00730949 0.0835572 0. 0. 0. 0. 0. [ 0.13339096 0.13339096 0. 0. 0. 0. 0.
0.06926091 0.06926091 0. 0.07624771 0. 0.03957485 0. 0.00730949 0. 0. 0. 0. 0.
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. 0. 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 References
---------- ----------
...@@ -319,8 +309,9 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None): ...@@ -319,8 +309,9 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None):
University, September 2003. University, September 2003.
.. [boykov-experimental-2004] Yuri Boykov and Vladimir Kolmogorov, "An .. [boykov-experimental-2004] Yuri Boykov and Vladimir Kolmogorov, "An
Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy 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. Machine Intelligence, vol. 26, no. 9, pp. 1124-1137, Sept. 2004.
:doi:`10.1109/TPAMI.2004.60`
""" """
_check_prop_scalar(capacity, "capacity") _check_prop_scalar(capacity, "capacity")
if residual == None: if residual == None:
...@@ -328,6 +319,9 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None): ...@@ -328,6 +319,9 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None):
_check_prop_scalar(residual, "residual") _check_prop_scalar(residual, "residual")
_check_prop_writable(residual, "residual") _check_prop_writable(residual, "residual")
if not g.is_directed():
raise ValueError("The graph provided must be directed!")
libgraph_tool_flow.\ libgraph_tool_flow.\
kolmogorov_max_flow(g._Graph__graph, int(source), int(target), kolmogorov_max_flow(g._Graph__graph, int(source), int(target),
_prop("e", g, capacity), _prop("e", g, capacity),
...@@ -385,9 +379,12 @@ def max_cardinality_matching(g, match=None): ...@@ -385,9 +379,12 @@ def max_cardinality_matching(g, match=None):
_check_prop_scalar(match, "match") _check_prop_scalar(match, "match")
_check_prop_writable(match, "match") _check_prop_writable(match, "match")
try:
g.stash_filter(directed=True) g.stash_filter(directed=True)
g.set_directed(False) g.set_directed(False)
check = libgraph_tool_flow.\ check = libgraph_tool_flow.\
max_cardinality_matching(g._Graph__graph, _prop("e", g, match)) max_cardinality_matching(g._Graph__graph, _prop("e", g, match))
finally:
g.pop_filter(directed=True) g.pop_filter(directed=True)
return match, check 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