diff --git a/src/graph/graph_bind.cc b/src/graph/graph_bind.cc index 3f1076da4360cae631e1bd08e52f75cd21c1003d..f440c630642be417e2afcbde845d23b21d87f906 100644 --- a/src/graph/graph_bind.cc +++ b/src/graph/graph_bind.cc @@ -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::null_vertex();}); } diff --git a/src/graph/search/graph_bfs.cc b/src/graph/search/graph_bfs.cc index ea34655c95e425addd55308e0d42f9329274b145..811b06a065722f7964dac63045439f128fc2e706 100644 --- a/src/graph/search/graph_bfs.cc +++ b/src/graph/search/graph_bfs.cc @@ -106,20 +106,28 @@ private: boost::python::object _vis; }; -struct do_bfs -{ - template - 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() - (g, std::bind(do_bfs(), std::placeholders::_1, s, - BFSVisitorWrapper(g, vis)))(); + (gi, + [&](auto &g) + { + typedef typename std::remove_reference::type g_t; + typename vprop_map_t::type + color(get(vertex_index_t(), g)); + auto visw = BFSVisitorWrapper(gi, vis); + auto v = vertex(s, g); + if (v == graph_traits::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() - (g, std::bind(do_bfs(), std::placeholders::_1, s, vis))(); + (g, + [&](auto &g) + { + typedef typename std::remove_reference::type g_t; + typename vprop_map_t::type + color(get(vertex_index_t(), g)); + + auto v = vertex(s, g); + if (v == graph_traits::null_vertex()) + { + for (auto u : vertices_range(g)) + { + if (color[u] == color_traits::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 diff --git a/src/graph/search/graph_dfs.cc b/src/graph/search/graph_dfs.cc index a63921368927d3b4bbe3cccb15f341524f571ac4..439929cda4718204c8d3f3ea83505d13f06fe720 100644 --- a/src/graph/search/graph_dfs.cc +++ b/src/graph/search/graph_dfs.cc @@ -90,25 +90,22 @@ private: python::object _vis; }; -struct do_dfs +void dfs_search(GraphInterface& gi, size_t s, python::object vis) { - template - void operator()(Graph& g, VertexIndexMap vertex_index, size_t s, - Visitor vis) const - { - typename property_map_type::apply::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() - (g, std::bind(do_dfs(), std::placeholders::_1, g.get_vertex_index(), - s, DFSVisitorWrapper(g, vis)))(); + run_action() + (gi, + [&](auto &g) + { + typedef typename std::remove_reference::type g_t; + typename vprop_map_t::type + color(get(vertex_index_t(), g)); + auto visw = DFSVisitorWrapper(gi, vis); + auto v = vertex(s, g); + if (v == graph_traits::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() - (g, std::bind(do_dfs(), std::placeholders::_1, - g.get_vertex_index(), s, vis))(); + (g, + [&](auto &g) + { + typedef typename std::remove_reference::type g_t; + typename vprop_map_t::type + color(get(vertex_index_t(), g)); + auto v = vertex(s, g); + if (v == graph_traits::null_vertex()) + depth_first_search(g, vis, color); + else + depth_first_visit(g, v, vis, color); + })(); }; return boost::python::object(CoroGenerator(dispatch)); #else diff --git a/src/graph/search/graph_dijkstra.cc b/src/graph/search/graph_dijkstra.cc index 58356044000575099e8e3ea214a3f303abdbf814..898c07514c27639e591e069001d9a33c69c3c969 100644 --- a/src/graph/search/graph_dijkstra.cc +++ b/src/graph/search/graph_dijkstra.cc @@ -140,11 +140,33 @@ struct do_djk_search typedef typename graph_traits::edge_descriptor edge_t; DynamicPropertyMapWrap 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::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::value_type dtype_t; dtype_t z = python::extract(range.first); dtype_t i = python::extract(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::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(), + boost::closed_plus(), 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)); + } } }; diff --git a/src/graph_tool/__init__.py b/src/graph_tool/__init__.py index 13d48621d4692a6cba785e47e1d9062fc5b4af02..bbd5cd60915878d453b97b8818d7c987418ad428 100644 --- a/src/graph_tool/__init__.py +++ b/src/graph_tool/__init__.py @@ -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): diff --git a/src/graph_tool/search/__init__.py b/src/graph_tool/search/__init__.py index 6977511cbc08803ac7ff1012d18d5f6142da0715..0291a9fe25a09423e8ede90ce8e798fd446ad002 100644 --- a/src/graph_tool/search/__init__.py +++ b/src/graph_tool/search/__init__.py @@ -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,