Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Tiago Peixoto
graph-tool
Commits
615a8925
Commit
615a8925
authored
Dec 17, 2015
by
Tiago Peixoto
Browse files
Implement all_shortest_paths()
parent
c49a9dd6
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/graph/topology/graph_distance.cc
View file @
615a8925
...
...
@@ -19,6 +19,7 @@
#include
"graph_filtering.hh"
#include
"graph_properties.hh"
#include
"graph_selectors.hh"
#include
"graph_python_interface.hh"
#include
"numpy_bind.hh"
#include
"hash_map_wrap.hh"
...
...
@@ -28,6 +29,10 @@
#include
<boost/python/stl_iterator.hpp>
#include
<boost/python.hpp>
#ifdef HAVE_BOOST_COROUTINE
#include
<boost/coroutine/all.hpp>
#endif // HAVE_BOOST_COROUTINE
using
namespace
std
;
using
namespace
boost
;
using
namespace
graph_tool
;
...
...
@@ -407,7 +412,96 @@ void get_dists(GraphInterface& gi, size_t source, boost::python::object tgt,
}
}
template
<
class
Graph
,
class
Dist
,
class
Pred
,
class
Preds
>
void
get_all_preds
(
Graph
g
,
Dist
dist
,
Pred
pred
,
Preds
preds
)
{
int
i
,
N
=
num_vertices
(
g
);
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100)
for
(
i
=
0
;
i
<
N
;
++
i
)
{
size_t
v
=
vertex
(
i
,
g
);
if
(
v
==
graph_traits
<
Graph
>::
null_vertex
())
continue
;
if
(
size_t
(
pred
[
v
])
==
v
)
continue
;
auto
d
=
dist
[
pred
[
v
]];
for
(
auto
e
:
in_or_out_edges_range
(
v
,
g
))
{
auto
u
=
boost
::
is_directed
(
g
)
?
source
(
e
,
g
)
:
target
(
e
,
g
);
if
(
dist
[
u
]
==
d
)
preds
[
v
].
push_back
(
u
);
}
}
};
void
do_get_all_preds
(
GraphInterface
&
gi
,
boost
::
any
adist
,
boost
::
any
apred
,
boost
::
any
apreds
)
{
typedef
property_map_type
::
apply
<
int64_t
,
GraphInterface
::
vertex_index_map_t
>::
type
pred_map_t
;
typedef
property_map_type
::
apply
<
vector
<
int64_t
>
,
GraphInterface
::
vertex_index_map_t
>::
type
preds_map_t
;
pred_map_t
pred
=
any_cast
<
pred_map_t
>
(
apred
);
preds_map_t
preds
=
any_cast
<
preds_map_t
>
(
apreds
);
run_action
<>
()
(
gi
,
[
&
](
auto
&
g
,
auto
dist
)
{
get_all_preds
(
g
,
dist
,
pred
.
get_unchecked
(
num_vertices
(
g
)),
preds
.
get_unchecked
(
num_vertices
(
g
)));},
vertex_scalar_properties
())(
adist
);
}
template
<
class
Pred
,
class
Yield
>
void
get_all_paths
(
size_t
s
,
size_t
t
,
Pred
pred
,
Yield
&
yield
)
{
vector
<
size_t
>
path
;
vector
<
pair
<
size_t
,
size_t
>>
stack
=
{{
t
,
0
}};
while
(
!
stack
.
empty
())
{
size_t
v
,
i
;
std
::
tie
(
v
,
i
)
=
stack
.
back
();
if
(
v
==
s
)
{
path
.
clear
();
for
(
auto
iter
=
stack
.
rbegin
();
iter
!=
stack
.
rend
();
++
iter
)
path
.
push_back
(
iter
->
first
);
yield
(
wrap_vector_owned
<
size_t
>
(
path
));
}
if
(
pred
[
v
].
size
()
>
i
)
{
stack
.
emplace_back
(
pred
[
v
][
i
],
0
);
}
else
{
stack
.
pop_back
();
if
(
!
stack
.
empty
())
++
stack
.
back
().
second
;
}
}
};
python
::
object
do_get_all_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
);},
vertex_scalar_vector_properties
())(
apred
);
};
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_paths"
,
&
do_get_all_paths
);
};
src/graph_tool/topology/__init__.py
View file @
615a8925
...
...
@@ -30,6 +30,8 @@ Summary
shortest_distance
shortest_path
all_shortest_paths
all_predecessors
pseudo_diameter
similarity
isomorphism
...
...
@@ -78,9 +80,9 @@ __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"sequential_vertex_coloring"
,
"label_components"
,
"label_largest_component"
,
"label_biconnected_components"
,
"label_out_component"
,
"kcore_decomposition"
,
"shortest_distance"
,
"shortest_path"
,
"
pseudo_diameter"
,
"is_bipartite"
,
"is_DAG
"
,
"
is_planar"
,
"make_maximal_planar"
,
"similarity"
,
"edge_reciprocity"
]
"shortest_path"
,
"
all_shortest_paths"
,
"all_predecessors
"
,
"
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.
...
...
@@ -339,7 +341,7 @@ def subgraph_isomorphism(sub, g, max_n=0, vertex_label=None, edge_label=None,
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.101.5342
.. [cordella-subgraph-2004] L. P. Cordella, P. Foggia, C. Sansone, and M. Vento,
"A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs.",
IEEE Trans. Pattern Anal. Mach. Intell., vol. 26, no. 10, pp. 1367-1372, 2004.
IEEE Trans. Pattern Anal. Mach. Intell., vol. 26, no. 10, pp. 1367-1372, 2004.
:doi:`10.1109/TPAMI.2004.75`
.. [boost-subgraph-iso] http://www.boost.org/libs/graph/doc/vf2_sub_graph_iso.html
.. [subgraph-isormophism-wikipedia] http://en.wikipedia.org/wiki/Subgraph_isomorphism_problem
...
...
@@ -1142,7 +1144,7 @@ def shortest_distance(g, source=None, target=None, weights=None,
The edge weights. If provided, the shortest path will correspond to the
minimal sum of weights.
negative_weights : ``bool`` (optional, default: ``False``)
If `True`, this will trigger the use of Bellman-Ford algorithm.
If `True`, this will trigger the use of
the
Bellman-Ford algorithm.
Ignored if ``source`` is ``None``.
max_dist : scalar value (optional, default: ``None``)
If specified, this limits the maximum distance of the vertices
...
...
@@ -1316,7 +1318,7 @@ def shortest_distance(g, source=None, target=None, weights=None,
def
shortest_path
(
g
,
source
,
target
,
weights
=
None
,
negative_weights
=
False
,
pred_map
=
None
):
"""Return the shortest path from `source` to `target`.
"""Return the shortest path from
`
`source`
`
to
`
`target`
`
.
Parameters
----------
...
...
@@ -1329,7 +1331,7 @@ def shortest_path(g, source, target, weights=None, negative_weights=False,
weights : :class:`~graph_tool.PropertyMap` (optional, default: None)
The edge weights.
negative_weights : ``bool`` (optional, default: ``False``)
If `True`, this will trigger the use of Bellman-Ford algorithm.
If
`
`True`
`
, this will trigger the use of
the
Bellman-Ford algorithm.
pred_map : :class:`~graph_tool.PropertyMap` (optional, default: None)
Vertex property map with the predecessors in the search tree. If this is
provided, the shortest paths are not computed, and are obtained directly
...
...
@@ -1419,6 +1421,117 @@ def shortest_path(g, source, target, weights=None, negative_weights=False,
v
=
p
return
vlist
,
elist
def
all_predecessors
(
g
,
dist_map
,
pred_map
):
"""Return a property map with all possible predecessors in the search tree
determined by ``dist_map`` and ``pred_map``.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
dist_map : :class:`~graph_tool.PropertyMap`
Vertex property map with the distances from ``source`` to all other
vertices.
pred_map : :class:`~graph_tool.PropertyMap` (optional, default: None)
Vertex property map with the predecessors in the search tree.
Returns
-------
all_preds_map : :class:`~graph_tool.PropertyMap`
Vector-valued vertex property map with all possible predecessors in the
search tree.
"""
preds
=
g
.
new_vertex_property
(
"vector<int64_t>"
)
libgraph_tool_topology
.
get_all_preds
(
g
.
_Graph__graph
,
_prop
(
"v"
,
g
,
dist_map
),
_prop
(
"v"
,
g
,
pred_map
),
_prop
(
"v"
,
g
,
preds
))
return
preds
def
all_shortest_paths
(
g
,
source
,
target
,
weights
=
None
,
negative_weights
=
False
,
dist_map
=
None
,
pred_map
=
None
,
all_preds_map
=
None
):
"""Return an iterator over all shortest 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.
weights : :class:`~graph_tool.PropertyMap` (optional, default: None)
The edge weights.
negative_weights : ``bool`` (optional, default: ``False``)
If ``True``, this will trigger the use of the Bellman-Ford algorithm.
dist_map : :class:`~graph_tool.PropertyMap` (optional, default: None)
Vertex property map with the distances from ``source`` to all other
vertices.
pred_map : :class:`~graph_tool.PropertyMap` (optional, default: None)
Vertex property map with the predecessors in the search tree. If this is
provided, the shortest paths are not computed, and are obtained directly
from this map.
all_preds_map : :class:`~graph_tool.PropertyMap` (optional, default: None)
Vector-valued vertex property map with all possible predecessors in the
search tree. If this is provided, the shortest paths are obtained
directly from this map.
Returns
-------
path_iterator : iterator over a sequence of integers
Iterator over sequences of vertices from `source` to `target` in the
shortest path.
Notes
-----
The paths are computed with a breadth-first search (BFS) or Dijkstra's
algorithm [dijkstra]_, if weights are given. If ``negative_weights ==
True``, the Bellman-Ford algorithm is used [bellman_ford]_, which accepts
negative weights, as long as there are no negative loops.
If both ``dist_map`` and ``pred_map` are provided, the search is not
actually performed.
Examples
--------
>>> g = gt.collection.data["pgp-strong-2009"]
>>> for path in gt.all_shortest_paths(g, 92, 45):
... print(path)
[ 92 107 2176 7027 26 21 45]
[ 92 107 2176 7033 26 21 45]
[ 92 82 94 5877 5879 34 45]
[ 92 89 94 5877 5879 34 45]
References
----------
.. [bfs] Edward Moore, "The shortest path through a maze", International
Symposium on the Theory of Switching (1959), Harvard University
Press
.. [bfs-boost] http://www.boost.org/libs/graph/doc/breadth_first_search.html
.. [dijkstra] E. Dijkstra, "A note on two problems in connexion with
graphs." Numerische Mathematik, 1:269-271, 1959.
.. [dijkstra-boost] http://www.boost.org/libs/graph/doc/dijkstra_shortest_paths.html
.. [bellman-ford] http://www.boost.org/libs/graph/doc/bellman_ford_shortest.html
"""
if
dist_map
is
None
or
pred_map
is
None
:
dist_map
,
pred_map
=
shortest_distance
(
g
,
source
,
weights
=
weights
,
negative_weights
=
negative_weights
,
pred_map
=
True
)
if
all_preds_map
is
None
:
all_preds_map
=
all_predecessors
(
g
,
dist_map
,
pred_map
)
path_iterator
=
libgraph_tool_topology
.
get_all_paths
(
g
.
_Graph__graph
,
int
(
source
),
int
(
target
),
_prop
(
"v"
,
g
,
all_preds_map
))
return
path_iterator
def
pseudo_diameter
(
g
,
source
=
None
,
weights
=
None
):
"""
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment