Commit a4abd055 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Implement all_paths()

This fixes issue #278.
parent 1989b4b5
Pipeline #119 failed with stage
......@@ -455,7 +455,7 @@ void do_get_all_preds(GraphInterface& gi, boost::any adist,
template <class Pred, class Yield>
void get_all_paths(size_t s, size_t t, Pred pred, Yield& yield)
void get_all_shortest_paths(size_t s, size_t t, Pred pred, Yield& yield)
{
vector<size_t> path;
vector<pair<size_t, size_t>> stack = {{t, 0}};
......@@ -483,14 +483,15 @@ void get_all_paths(size_t s, size_t t, Pred pred, Yield& yield)
}
};
python::object do_get_all_paths(GraphInterface& gi, size_t s, size_t t,
boost::any apred)
python::object do_get_all_shortest_paths(GraphInterface& gi, size_t s, size_t t,
boost::any apred)
{
#ifdef HAVE_BOOST_COROUTINE
auto dispatch = [&](auto& yield)
{
run_action<>()
(gi, [&](auto&, auto pred) {get_all_paths(s, t, pred, yield);},
(gi, [&](auto&, auto pred)
{get_all_shortest_paths(s, t, pred, yield);},
vertex_scalar_vector_properties())(apred);
};
return python::object(CoroGenerator(dispatch));
......@@ -499,9 +500,65 @@ python::object do_get_all_paths(GraphInterface& gi, size_t s, size_t t,
#endif // HAVE_BOOST_COROUTINE
}
template <class Graph, class Yield>
void get_all_paths(size_t s, size_t t, size_t cutoff, Yield& yield, Graph& g)
{
typedef typename graph_traits<Graph>::out_edge_iterator eiter_t;
typedef std::pair<eiter_t, eiter_t> item_t;
vector<item_t> stack = {out_edges(s, g)};
while (!stack.empty())
{
auto& pos = stack.back();
if (pos.first == pos.second || stack.size() > cutoff)
{
stack.pop_back();
if (!stack.empty())
++stack.back().first;
continue;
}
auto v = target(*pos.first, g);
if (v == t)
{
vector<size_t> path = {s};
for (auto& ei : stack)
path.push_back(target(*ei.first, g));
yield(wrap_vector_owned<size_t>(path));
stack.pop_back();
if (!stack.empty())
++stack.back().first;
}
else
{
stack.push_back(out_edges(v, g));
}
}
};
python::object do_get_all_paths(GraphInterface& gi, size_t s, size_t t,
size_t cutoff)
{
#ifdef HAVE_BOOST_COROUTINE
auto dispatch = [&](auto& yield)
{
run_action<>()
(gi, [&](auto& g) {get_all_paths(s, t, cutoff, yield, g);})();
};
return python::object(CoroGenerator(dispatch));
#else
throw GraphException("This functionality is not available because boost::coroutine was not found at compile-time");
#endif // HAVE_BOOST_COROUTINE
}
void export_dists()
{
python::def("get_dists", &get_dists);
python::def("get_all_preds", &do_get_all_preds);
python::def("get_all_shortest_paths", &do_get_all_shortest_paths);
python::def("get_all_paths", &do_get_all_paths);
};
......@@ -32,6 +32,7 @@ Summary
shortest_path
all_shortest_paths
all_predecessors
all_paths
pseudo_diameter
similarity
isomorphism
......@@ -81,8 +82,8 @@ __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"label_largest_component", "label_biconnected_components",
"label_out_component", "kcore_decomposition", "shortest_distance",
"shortest_path", "all_shortest_paths", "all_predecessors",
"pseudo_diameter", "is_bipartite", "is_DAG", "is_planar",
"make_maximal_planar", "similarity", "edge_reciprocity"]
"all_paths", "pseudo_diameter", "is_bipartite", "is_DAG",
"is_planar", "make_maximal_planar", "similarity", "edge_reciprocity"]
def similarity(g1, g2, label1=None, label2=None, norm=True):
r"""Return the adjacency similarity between the two graphs.
......@@ -1526,10 +1527,61 @@ def all_shortest_paths(g, source, target, weights=None, negative_weights=False,
if all_preds_map is None:
all_preds_map = all_predecessors(g, dist_map, pred_map)
path_iterator = \
libgraph_tool_topology.get_all_shortest_paths(g._Graph__graph,
int(source),
int(target),
_prop("v", g, all_preds_map))
return path_iterator
def all_paths(g, source, target, cutoff=None):
"""Return an iterator over all paths from `source` to `target`.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex of the search.
target : :class:`~graph_tool.Vertex`
Target vertex of the search.
cutoff : `int` (optional, default: None)
Maximum path length.
Returns
-------
path_iterator : iterator over a sequence of integers
Iterator over sequences of vertices from `source` to `target` in the
path.
Notes
-----
The algorithm uses a depth-first search to find all the paths.
The total number of paths between any two vertices can be quite large,
possibly scaling as :math:`O(V!)`.
Examples
--------
>>> g = gt.collection.data[""]
>>> for path in gt.all_paths(g, 13, 2, cutoff=2):
... print(path)
[13 15 2]
[13 60 2]
[13 64 2]
[ 13 100 2]
[ 13 106 2]
[13 2]
"""
if cutoff is None:
cutoff = g.num_edges() + 1
path_iterator = libgraph_tool_topology.get_all_paths(g._Graph__graph,
int(source),
int(target),
_prop("v", g, all_preds_map))
cutoff)
return path_iterator
......
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