Commit fb37166a authored by Tiago Peixoto's avatar Tiago Peixoto

Add support for iterating over all vertices in {dfs,bfs,dijkstra}_{search,iterator}()

parent 5752f5eb
Pipeline #262 passed with stage
in 184 minutes and 22 seconds
......@@ -576,4 +576,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
.add_property("gcc_version", &LibInfo::GetGCCVersion);
def("get_graph_type", &get_graph_type);
def("get_null_vertex",
+[](){ return graph_traits<GraphInterface::multigraph_t>::null_vertex();});
}
......@@ -106,20 +106,28 @@ private:
boost::python::object _vis;
};
struct do_bfs
{
template <class Graph, class Visitor>
void operator()(Graph& g, size_t s, Visitor vis) const
{
breadth_first_search(g, vertex(s, g), visitor(vis));
}
};
void bfs_search(GraphInterface& g, size_t s, python::object vis)
void bfs_search(GraphInterface& gi, size_t s, python::object vis)
{
run_action<graph_tool::all_graph_views,mpl::true_>()
(g, std::bind(do_bfs(), std::placeholders::_1, s,
BFSVisitorWrapper(g, vis)))();
(gi,
[&](auto &g)
{
typedef typename std::remove_reference<decltype(g)>::type g_t;
typename vprop_map_t<default_color_type>::type
color(get(vertex_index_t(), g));
auto visw = BFSVisitorWrapper(gi, vis);
auto v = vertex(s, g);
if (v == graph_traits<g_t>::null_vertex())
{
for (auto u : vertices_range(g))
breadth_first_search(g, u, visitor(visw).color_map(color));
}
else
{
breadth_first_visit(g, v, visitor(visw).color_map(color));
}
})();
}
#ifdef HAVE_BOOST_COROUTINE
......@@ -152,7 +160,28 @@ boost::python::object bfs_search_generator(GraphInterface& g, size_t s)
{
BFSGeneratorVisitor vis(g, yield);
run_action<graph_tool::all_graph_views,mpl::true_>()
(g, std::bind(do_bfs(), std::placeholders::_1, s, vis))();
(g,
[&](auto &g)
{
typedef typename std::remove_reference<decltype(g)>::type g_t;
typename vprop_map_t<default_color_type>::type
color(get(vertex_index_t(), g));
auto v = vertex(s, g);
if (v == graph_traits<g_t>::null_vertex())
{
for (auto u : vertices_range(g))
{
if (color[u] == color_traits<default_color_type>::black())
continue;
breadth_first_visit(g, u, visitor(vis).color_map(color));
}
}
else
{
breadth_first_visit(g, v, visitor(vis).color_map(color));
}
})();
};
return boost::python::object(CoroGenerator(dispatch));
#else
......
......@@ -90,25 +90,22 @@ private:
python::object _vis;
};
struct do_dfs
void dfs_search(GraphInterface& gi, size_t s, python::object vis)
{
template <class Graph, class VertexIndexMap, class Visitor>
void operator()(Graph& g, VertexIndexMap vertex_index, size_t s,
Visitor vis) const
{
typename property_map_type::apply<default_color_type,
VertexIndexMap>::type
color(vertex_index);
depth_first_visit(g, vertex(s, g), vis, color);
}
};
void dfs_search(GraphInterface& g, size_t s, python::object vis)
{
run_action<graph_tool::all_graph_views,mpl::true_>()
(g, std::bind(do_dfs(), std::placeholders::_1, g.get_vertex_index(),
s, DFSVisitorWrapper(g, vis)))();
run_action<graph_tool::all_graph_views, mpl::true_>()
(gi,
[&](auto &g)
{
typedef typename std::remove_reference<decltype(g)>::type g_t;
typename vprop_map_t<default_color_type>::type
color(get(vertex_index_t(), g));
auto visw = DFSVisitorWrapper(gi, vis);
auto v = vertex(s, g);
if (v == graph_traits<g_t>::null_vertex())
depth_first_search(g, visw, color);
else
depth_first_visit(g, v, visw, color);
})();
}
#ifdef HAVE_BOOST_COROUTINE
......@@ -142,8 +139,18 @@ boost::python::object dfs_search_generator(GraphInterface& g, size_t s)
{
DFSGeneratorVisitor vis(g, yield);
run_action<graph_tool::all_graph_views,mpl::true_>()
(g, std::bind(do_dfs(), std::placeholders::_1,
g.get_vertex_index(), s, vis))();
(g,
[&](auto &g)
{
typedef typename std::remove_reference<decltype(g)>::type g_t;
typename vprop_map_t<default_color_type>::type
color(get(vertex_index_t(), g));
auto v = vertex(s, g);
if (v == graph_traits<g_t>::null_vertex())
depth_first_search(g, vis, color);
else
depth_first_visit(g, v, vis, color);
})();
};
return boost::python::object(CoroGenerator(dispatch));
#else
......
......@@ -140,11 +140,33 @@ struct do_djk_search
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
DynamicPropertyMapWrap<dtype_t, edge_t> weight(aweight,
edge_properties());
dijkstra_shortest_paths_no_color_map
(g, vertex(s, g), visitor(vis).weight_map(weight).
predecessor_map(pred_map).
distance_map(dist).distance_compare(cmp).
distance_combine(cmb).distance_inf(i).distance_zero(z));
if (vertex(s, g) == graph_traits<Graph>::null_vertex())
{
for (auto u : vertices_range(g))
{
vis.initialize_vertex(u, g);
put(dist, u, i);
put(pred_map, u, u);
}
for (auto u : vertices_range(g))
{
if (dist[u] != i)
continue;
dist[u] = z;
dijkstra_shortest_paths_no_color_map_no_init
(g, u, pred_map, dist, weight, get(vertex_index_t(), g),
cmp, cmb, i, z, vis);
}
}
else
{
dijkstra_shortest_paths_no_color_map
(g, vertex(s, g), visitor(vis).weight_map(weight).
predecessor_map(pred_map).
distance_map(dist).distance_compare(cmp).
distance_combine(cmb).distance_inf(i).distance_zero(z));
}
}
};
......@@ -158,9 +180,31 @@ struct do_djk_search_fast
typedef typename property_traits<DistanceMap>::value_type dtype_t;
dtype_t z = python::extract<dtype_t>(range.first);
dtype_t i = python::extract<dtype_t>(range.second);
dijkstra_shortest_paths_no_color_map
(g, vertex(s, g), visitor(vis).weight_map(weight).
distance_map(dist).distance_inf(i).distance_zero(z));
if (vertex(s, g) == graph_traits<Graph>::null_vertex())
{
for (auto u : vertices_range(g))
{
vis.initialize_vertex(u, g);
put(dist, u, i);
}
for (auto u : vertices_range(g))
{
if (dist[u] != i)
continue;
dist[u] = z;
dijkstra_shortest_paths_no_color_map_no_init
(g, u, dummy_property_map(), dist, weight,
get(vertex_index_t(), g), std::less<dtype_t>(),
boost::closed_plus<dtype_t>(), i, z, vis);
}
}
else
{
dijkstra_shortest_paths_no_color_map
(g, vertex(s, g), visitor(vis).weight_map(weight).
distance_map(dist).distance_inf(i).distance_zero(z));
}
}
};
......
......@@ -3261,6 +3261,7 @@ VertexBase.is_valid = Vertex.is_valid
Vertex = VertexBase
Vertex.__name__ = "Vertex"
_get_null_vertex = libcore.get_null_vertex
# Add convenience function to vector classes
def _get_array_view(self):
......
......@@ -92,7 +92,7 @@ if sys.version_info < (3,):
from .. dl_import import dl_import
dl_import("from . import libgraph_tool_search")
from .. import _prop, _python_type
from .. import _prop, _python_type, _get_null_vertex
import weakref
import numpy
......@@ -157,15 +157,17 @@ class BFSVisitor(object):
return
def bfs_search(g, source, visitor=BFSVisitor()):
def bfs_search(g, source=None, visitor=BFSVisitor()):
r"""Breadth-first traversal of a directed or undirected graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
visitor : :class:`~graph_tool.search.BFSVisitor` (optional, default: ``BFSVisitor()``)
A visitor object that is invoked at the event points inside the
algorithm. This should be a subclass of
......@@ -284,12 +286,16 @@ def bfs_search(g, source, visitor=BFSVisitor()):
"""
try:
if source is None:
source = _get_null_vertex()
else:
source = int(source)
libgraph_tool_search.bfs_search(g._Graph__graph,
int(source), visitor)
source, visitor)
except StopSearch:
pass
def bfs_iterator(g, source):
def bfs_iterator(g, source=None):
r"""Return an iterator of the edges corresponding to a breath-first traversal of
the graph.
......@@ -297,8 +303,10 @@ def bfs_iterator(g, source):
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
Returns
-------
......@@ -341,8 +349,11 @@ def bfs_iterator(g, source):
.. [bfs-bgl] http://www.boost.org/doc/libs/release/libs/graph/doc/breadth_first_search.html
.. [bfs-wikipedia] http://en.wikipedia.org/wiki/Breadth-first_search
"""
return libgraph_tool_search.bfs_search_generator(g._Graph__graph, int(source))
if source is None:
source = _get_null_vertex()
else:
source = int(source)
return libgraph_tool_search.bfs_search_generator(g._Graph__graph, source)
class DFSVisitor(object):
......@@ -415,15 +426,17 @@ class DFSVisitor(object):
return
def dfs_search(g, source, visitor=DFSVisitor()):
def dfs_search(g, source=None, visitor=DFSVisitor()):
r"""Depth-first traversal of a directed or undirected graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
visitor : :class:`~graph_tool.search.DFSVisitor` (optional, default: ``DFSVisitor()``)
A visitor object that is invoked at the event points inside the
algorithm. This should be a subclass of
......@@ -563,15 +576,20 @@ def dfs_search(g, source, visitor=DFSVisitor()):
----------
.. [dfs-bgl] http://www.boost.org/doc/libs/release/libs/graph/doc/depth_first_search.html
.. [dfs-wikipedia] http://en.wikipedia.org/wiki/Depth-first_search
"""
try:
if source is None:
source = _get_null_vertex()
else:
source = int(source)
libgraph_tool_search.dfs_search(g._Graph__graph,
int(source), visitor)
source, visitor)
except StopSearch:
pass
def dfs_iterator(g, source):
def dfs_iterator(g, source=None):
r"""Return an iterator of the edges corresponding to a depth-first traversal of
the graph.
......@@ -579,8 +597,10 @@ def dfs_iterator(g, source):
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
Returns
-------
......@@ -622,7 +642,11 @@ def dfs_iterator(g, source):
.. [dfs-wikipedia] http://en.wikipedia.org/wiki/Depth-first_search
"""
return libgraph_tool_search.dfs_search_generator(g._Graph__graph, int(source))
if source is None:
source = _get_null_vertex()
else:
source = int(source)
return libgraph_tool_search.dfs_search_generator(g._Graph__graph, source)
class DijkstraVisitor(object):
r"""A visitor object that is invoked at the event-points inside the
......@@ -686,7 +710,7 @@ class DijkstraVisitor(object):
return
def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
def dijkstra_search(g, weight, source=None, visitor=DijkstraVisitor(), dist_map=None,
pred_map=None, combine=lambda a, b: a + b,
compare=lambda a, b: a < b, zero=0, infinity=numpy.inf):
r"""Dijsktra traversal of a directed or undirected graph, with non-negative weights.
......@@ -695,10 +719,12 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
weight : :class:`~graph_tool.PropertyMap`
Edge property map with weight values.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
visitor : :class:`~graph_tool.search.DijkstraVisitor` (optional, default: ``DijkstraVisitor()``)
A visitor object that is invoked at the event points inside the
algorithm. This should be a subclass of
......@@ -815,7 +841,7 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
With the above class defined, we can perform the Dijkstra search as follows.
>>> time = g.new_vertex_property("int")
>>> dist, pred = gt.dijkstra_search(g, g.vertex(0), weight, VisitorExample(name, time))
>>> dist, pred = gt.dijkstra_search(g, weight, g.vertex(0), VisitorExample(name, time))
--> Bob has been discovered!
edge (Bob, Eve) has been examined...
edge (Bob, Eve) has been relaxed...
......@@ -910,8 +936,12 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
infinity = _python_type(dist_map.value_type())(infinity)
try:
if source is None:
source = _get_null_vertex()
else:
source = int(source)
libgraph_tool_search.dijkstra_search(g._Graph__graph,
int(source),
source,
_prop("v", g, dist_map),
_prop("v", g, pred_map),
_prop("e", g, weight), visitor,
......@@ -921,7 +951,7 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
return dist_map, pred_map
def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
def dijkstra_iterator(g, weight, source=None, dist_map=None, combine=None,
compare=None, zero=0, infinity=numpy.inf):
r"""Return an iterator of the edges corresponding to a Dijkstra traversal of
the graph.
......@@ -930,10 +960,12 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
weight : :class:`~graph_tool.PropertyMap`
Edge property map with weight values.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
dist_map : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
A vertex property map where the distances from the source will be
stored.
......@@ -972,7 +1004,7 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
Examples
--------
>>> for e in gt.dijkstra_iterator(g, g.vertex(0), weight):
>>> for e in gt.dijkstra_iterator(g, weight, g.vertex(0)):
... print(name[e.source()], "->", name[e.target()])
Bob -> Eve
Bob -> Chuck
......@@ -1009,9 +1041,13 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
infinity = (weight.a.max() + 1) * g.num_vertices()
infinity = _python_type(dist_map.value_type())(infinity)
if source is None:
source = _get_null_vertex()
else:
source = int(source)
if compare is None and combine is None:
return libgraph_tool_search.dijkstra_generator_fast(g._Graph__graph,
int(source),
source,
_prop("v", g, dist_map),
_prop("e", g, weight),
zero, infinity)
......@@ -1021,7 +1057,7 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
if combine is None:
combine = lambda a, b: a + b
return libgraph_tool_search.dijkstra_generator(g._Graph__graph,
int(source),
source,
_prop("v", g, dist_map),
_prop("e", g, weight),
compare, combine,
......
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