Commit 45565cd1 authored by Tiago Peixoto's avatar Tiago Peixoto

Implement dfs/bfs/dijkstra/astar_iterator()

parent c68fd018
Pipeline #54 failed with stage
......@@ -202,7 +202,7 @@ echo "==========================="
dnl boost
AX_BOOST_BASE([[1.53.0]])
AX_BOOST_BASE([[1.55.0]])
AX_BOOST_PYTHON
if test "$BOOST_PYTHON_LIB" = ""; then
AC_MSG_ERROR([No usable boost::python found])
......@@ -215,7 +215,10 @@ AX_BOOST_REGEX
if test "$BOOST_REGEX_LIB" = ""; then
AC_MSG_ERROR([No usable boost::regex found])
fi
AX_BOOST_COROUTINE
if test "$BOOST_COROUTINE_LIB" = ""; then
AC_MSG_ERROR([No usable boost::coroutine found])
fi
AX_BOOST_GRAPH
if test "$BOOST_GRAPH_LIB" = ""; then
AC_MSG_ERROR([No usable boost::graph found])
......@@ -407,7 +410,7 @@ AC_SUBST(MOD_CPPFLAGS)
# default LIBADD flags for submodules
[MOD_LIBADD="${PYTHON_LDFLAGS} -l${BOOST_IOSTREAMS_LIB} -l${BOOST_PYTHON_LIB} \
-l${BOOST_REGEX_LIB} ${OPENMP_LDFLAGS} -lexpat"]
-l${BOOST_REGEX_LIB} ${BOOST_COROUTINE_LIB} ${OPENMP_LDFLAGS} -lexpat"]
AC_SUBST(MOD_LIBADD)
# needed for typeinfo objects to work across DSO boundaries.
......
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_coroutine.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_COROUTINE
#
# DESCRIPTION
#
# Test for Coroutine library from the Boost C++ libraries. The macro
# requires a preceding call to AX_BOOST_BASE. Further documentation is
# available at <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_COROUTINE_LIB)
#
# And sets:
#
# HAVE_BOOST_COROUTINE
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2008 Michael Tindal
# Copyright (c) 2013 Daniel Casimiro <dan.casimiro@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
AC_DEFUN([AX_BOOST_COROUTINE],
[
AC_ARG_WITH([boost-coroutine],
AS_HELP_STRING([--with-boost-coroutine@<:@=special-lib@:>@],
[use the Coroutine library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-coroutine=boost_coroutine-gcc-mt ]), [
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_coroutine_lib=""
else
want_boost="yes"
ax_boost_user_coroutine_lib="$withval"
fi
], [want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_BUILD])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::Coroutine library is available,
ax_cv_boost_coroutine,
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[@%:@include <boost/coroutine/all.hpp>]],
[[boost::coroutines::coroutine< void() > f;]])],
ax_cv_boost_coroutine=yes, ax_cv_boost_coroutine=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_coroutine" = "xyes"; then
AC_SUBST(BOOST_CPPFLAGS)
AC_DEFINE(HAVE_BOOST_COROUTINE,,[define if the Boost::Coroutine library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
if test "x$ax_boost_user_coroutine_lib" = "x"; then
for libextension in `ls $BOOSTLIBDIR/libboost_coroutine*.so* $BOOSTLIBDIR/libboost_coroutine*.dylib* $BOOSTLIBDIR/libboost_coroutine*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_coroutine.*\)\.so.*$;\1;' -e 's;^lib\(boost_coroutine.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_coroutine.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_COROUTINE_LIB="-l$ax_lib"; AC_SUBST(BOOST_COROUTINE_LIB) link_coroutine="yes"; break],
[link_coroutine="no"])
done
if test "x$link_coroutine" != "xyes"; then
for libextension in `ls $BOOSTLIBDIR/boost_coroutine*.dll* $BOOSTLIBDIR/boost_coroutine*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_coroutine.*\)\.dll.*$;\1;' -e 's;^\(boost_coroutine.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_COROUTINE_LIB="-l$ax_lib"; AC_SUBST(BOOST_COROUTINE_LIB) link_coroutine="yes"; break],
[link_coroutine="no"])
done
fi
else
for ax_lib in $ax_boost_user_coroutine_lib boost_coroutine-$ax_boost_user_coroutine_lib; do
AC_CHECK_LIB($ax_lib, exit,
[BOOST_COROUTINE_LIB="-l$ax_lib"; AC_SUBST(BOOST_COROUTINE_LIB) link_coroutine="yes"; break],
[link_coroutine="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_coroutine" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
......@@ -12,7 +12,7 @@ AM_CXXFLAGS =\
$(PYTHON_CPPFLAGS) \
$(BOOST_CPPFLAGS)
AM_CFLAGS=$(AM_CXXFLAGS)
AM_CFLAGS = $(AM_CXXFLAGS)
libgraph_tool_coredir = $(MOD_DIR)
libgraph_tool_core_LTLIBRARIES = libgraph_tool_core.la
......
......@@ -2,7 +2,7 @@
AM_CPPFLAGS = $(MOD_CPPFLAGS)
AM_CFLAGS=$(AM_CXXFLAGS)
AM_CFLAGS = $(AM_CXXFLAGS)
libgraph_tool_centralitydir = $(MOD_DIR)/centrality
......
......@@ -2,7 +2,7 @@
AM_CPPFLAGS = $(MOD_CPPFLAGS)
AM_CFLAGS=$(AM_CXXFLAGS)
AM_CFLAGS = $(AM_CXXFLAGS)
libgraph_tool_communitydir = $(MOD_DIR)/community
......
......@@ -412,18 +412,18 @@ struct export_python_interface
("VertexIterator", no_init)
.def("__iter__", objects::identity_function())
.def("__next__", &PythonIterator<Graph, PythonVertex<Graph>,
vertex_iterator>::Next)
vertex_iterator>::next)
.def("next", &PythonIterator<Graph, PythonVertex<Graph>,
vertex_iterator>::Next);
vertex_iterator>::next);
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
class_<PythonIterator<Graph, PythonEdge<Graph>,
edge_iterator> >("EdgeIterator", no_init)
.def("__iter__", objects::identity_function())
.def("__next__", &PythonIterator<Graph, PythonEdge<Graph>,
edge_iterator>::Next)
edge_iterator>::next)
.def("next", &PythonIterator<Graph, PythonEdge<Graph>,
edge_iterator>::Next);
edge_iterator>::next);
typedef typename graph_traits<Graph>::out_edge_iterator
out_edge_iterator;
......@@ -431,9 +431,9 @@ struct export_python_interface
out_edge_iterator> >("OutEdgeIterator", no_init)
.def("__iter__", objects::identity_function())
.def("__next__", &PythonIterator<Graph, PythonEdge<Graph>,
out_edge_iterator>::Next)
out_edge_iterator>::next)
.def("next", &PythonIterator<Graph, PythonEdge<Graph>,
out_edge_iterator>::Next);
out_edge_iterator>::next);
typedef typename graph_traits<Graph>::directed_category
directed_category;
......@@ -446,9 +446,9 @@ struct export_python_interface
in_edge_iterator> >("InEdgeIterator", no_init)
.def("__iter__", objects::identity_function())
.def("__next__", &PythonIterator<Graph, PythonEdge<Graph>,
in_edge_iterator>::Next)
in_edge_iterator>::next)
.def("next", &PythonIterator<Graph, PythonEdge<Graph>,
in_edge_iterator>::Next);
in_edge_iterator>::next);
}
}
......
......@@ -65,7 +65,7 @@ public:
PythonIterator(std::shared_ptr<Graph>& gp,
std::pair<Iterator,Iterator> e)
: _g(gp), _e(e) {}
Descriptor Next()
Descriptor next()
{
if (_e.first == _e.second)
boost::python::objects::stop_iteration_error();
......
......@@ -2,7 +2,7 @@
AM_CPPFLAGS = $(MOD_CPPFLAGS)
AM_CFLAGS=$(AM_CXXFLAGS)
AM_CFLAGS = $(AM_CXXFLAGS)
libgraph_tool_searchdir = $(MOD_DIR)/search
......
......@@ -20,6 +20,7 @@
#include <boost/python.hpp>
#include <boost/graph/astar_search.hpp>
#include <boost/coroutine/all.hpp>
#include "graph.hh"
#include "graph_selectors.hh"
......@@ -39,19 +40,16 @@ python::object operator |(const python::object& a, const T& b)
struct do_astar_search
{
template <class Graph, class DistanceMap>
void operator()(Graph& g, size_t s, DistanceMap dist, boost::any pred_map,
boost::any aweight, AStarVisitorWrapper vis, pair<AStarCmp,
AStarCmb> cmp, pair<python::object, python::object> range,
template <class Graph, class DistanceMap, class PredMap, class Visitor>
void operator()(Graph& g, size_t s, DistanceMap dist, PredMap pred,
boost::any aweight, Visitor vis, pair<AStarCmp, AStarCmb> cmp,
pair<python::object, python::object> range,
python::object h, GraphInterface& gi) const
{
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
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);
typedef typename property_map_type::
apply<int32_t, decltype(get(vertex_index, g))>::type pred_t;
pred_t pred = any_cast<pred_t>(pred_map);
checked_vector_property_map<default_color_type,
decltype(get(vertex_index, g))>
color(get(vertex_index, g));
......@@ -66,23 +64,138 @@ struct do_astar_search
}
};
struct do_astar_search_fast
{
template <class Graph, class DistanceMap, class WeightMap,
class Visitor>
void operator()(Graph& g, size_t s, DistanceMap dist,
WeightMap weight, Visitor vis,
pair<python::object, python::object> range,
python::object h, GraphInterface& gi) const
{
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);
astar_search(g, vertex(s, g), AStarH<Graph, dtype_t>(gi, g, h),
weight_map(weight).distance_map(dist).distance_zero(z).
distance_inf(i).visitor(vis));
}
};
void a_star_search(GraphInterface& g, size_t source, boost::any dist_map,
boost::any pred_map, boost::any weight, python::object vis,
python::object cmp, python::object cmb, python::object zero,
python::object inf, python::object h)
{
typedef typename property_map_type::
apply<int64_t, GraphInterface::vertex_index_map_t>::type pred_t;
pred_t pred = any_cast<pred_t>(pred_map);
run_action<graph_tool::detail::all_graph_views,mpl::true_>()
(g, std::bind(do_astar_search(), placeholders::_1, source,
placeholders::_2, pred_map, weight,
placeholders::_2, pred, weight,
AStarVisitorWrapper(g, vis), make_pair(AStarCmp(cmp),
AStarCmb(cmb)),
make_pair(zero, inf), h, std::ref(g)),
writable_vertex_properties())(dist_map);
}
typedef boost::coroutines::asymmetric_coroutine<boost::python::object> coro_t;
class AStarGeneratorVisitor : public astar_visitor<>
{
public:
AStarGeneratorVisitor(GraphInterface& gi,
coro_t::push_type& yield)
: _gi(gi), _yield(yield) {}
template <class Edge, class Graph>
void edge_relaxed(const Edge& e, Graph& g)
{
std::shared_ptr<Graph> gp = retrieve_graph_view<Graph>(_gi, g);
_yield(boost::python::object(PythonEdge<Graph>(gp, e)));
}
private:
GraphInterface& _gi;
coro_t::push_type& _yield;
};
class AStarGenerator
{
public:
template <class Dispatch>
AStarGenerator(Dispatch& dispatch)
: _coro(std::make_shared<coro_t::pull_type>(dispatch)),
_iter(begin(*_coro)), _end(end(*_coro)) {}
boost::python::object next()
{
if (_iter == _end)
boost::python::objects::stop_iteration_error();
boost::python::object oe = *_iter;
++_iter;
return oe;
}
private:
std::shared_ptr<coro_t::pull_type> _coro;
coro_t::pull_type::iterator _iter;
coro_t::pull_type::iterator _end;
};
boost::python::object astar_search_generator(GraphInterface& g,
size_t source,
boost::any dist_map,
boost::any weight,
python::object cmp,
python::object cmb,
python::object zero,
python::object inf,
python::object h)
{
auto dispatch = [&](auto& yield)
{
AStarGeneratorVisitor vis(g, yield);
run_action<graph_tool::detail::all_graph_views,mpl::true_>()
(g, std::bind(do_astar_search(), placeholders::_1, source,
placeholders::_2, dummy_property_map(), weight,
vis, make_pair(AStarCmp(cmp), AStarCmb(cmb)),
make_pair(zero, inf), h, std::ref(g)),
writable_vertex_properties())(dist_map);
};
return boost::python::object(AStarGenerator(dispatch));
}
boost::python::object astar_search_generator_fast(GraphInterface& g,
size_t source,
boost::any dist_map,
boost::any weight,
python::object zero,
python::object inf,
python::object h)
{
auto dispatch = [&](auto& yield)
{
AStarGeneratorVisitor vis(g, yield);
run_action<graph_tool::detail::all_graph_views,mpl::true_>()
(g, std::bind(do_astar_search_fast(), placeholders::_1, source,
placeholders::_2, placeholders::_3,
vis, make_pair(zero, inf), h, std::ref(g)),
writable_vertex_scalar_properties(),
edge_scalar_properties())(dist_map, weight);
};
return boost::python::object(AStarGenerator(dispatch));
}
void export_astar()
{
using namespace boost::python;
def("astar_search", &a_star_search);
def("astar_generator", &astar_search_generator);
def("astar_generator_fast", &astar_search_generator_fast);
class_<AStarGenerator>("AStarGenerator", no_init)
.def("__iter__", objects::identity_function())
.def("next", &AStarGenerator::next)
.def("__next__", &AStarGenerator::next);
}
......@@ -50,7 +50,7 @@ struct do_astar_search
decltype(get(vertex_index, g))>
color(get(vertex_index, g));
typedef typename property_map_type::
apply<int32_t, decltype(get(vertex_index, g))>::type pred_t;
apply<int64_t, decltype(get(vertex_index, g))>::type pred_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
DynamicPropertyMapWrap<dtype_t, edge_t> weight(aweight,
edge_properties());
......
......@@ -127,7 +127,7 @@ struct do_bf_search
dtype_t i = python::extract<dtype_t>(range.second);
typedef typename property_map_type::
apply<int32_t, decltype(get(vertex_index, g))>::type pred_t;
apply<int64_t, decltype(get(vertex_index, g))>::type pred_t;
pred_t pred = any_cast<pred_t>(pred_map);
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
DynamicPropertyMapWrap<dtype_t, edge_t> weight(aweight,
......
......@@ -20,6 +20,7 @@
#include <boost/python.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/coroutine/all.hpp>
#include "graph.hh"
#include "graph_selectors.hh"
......@@ -105,8 +106,8 @@ private:
struct do_bfs
{
template <class Graph>
void operator()(Graph& g, size_t s, BFSVisitorWrapper vis) const
template <class Graph, class Visitor>
void operator()(Graph& g, size_t s, Visitor vis) const
{
breadth_first_search(g, vertex(s, g), visitor(vis));
}
......@@ -119,8 +120,66 @@ void bfs_search(GraphInterface& g, size_t s, python::object vis)
BFSVisitorWrapper(g, vis)))();
}
typedef boost::coroutines::asymmetric_coroutine<boost::python::object> coro_t;
class BFSGeneratorVisitor : public bfs_visitor<>
{
public:
BFSGeneratorVisitor(GraphInterface& gi,
coro_t::push_type& yield)
: _gi(gi), _yield(yield) {}
template <class Edge, class Graph>
void tree_edge(const Edge& e, Graph& g)
{
std::shared_ptr<Graph> gp = retrieve_graph_view<Graph>(_gi, g);
_yield(boost::python::object(PythonEdge<Graph>(gp, e)));
}
private:
GraphInterface& _gi;
coro_t::push_type& _yield;
};
class BFSGenerator
{
public:
template <class Dispatch>
BFSGenerator(Dispatch& dispatch)
: _coro(std::make_shared<coro_t::pull_type>(dispatch)),
_iter(begin(*_coro)), _end(end(*_coro)) {}
boost::python::object next()
{
if (_iter == _end)
boost::python::objects::stop_iteration_error();
boost::python::object oe = *_iter;
++_iter;
return oe;
}
private:
std::shared_ptr<coro_t::pull_type> _coro;
coro_t::pull_type::iterator _iter;
coro_t::pull_type::iterator _end;
};
boost::python::object bfs_search_generator(GraphInterface& g, size_t s)
{
auto dispatch = [&](auto& yield)
{
BFSGeneratorVisitor vis(g, yield);
run_action<graph_tool::detail::all_graph_views,mpl::true_>()
(g, std::bind(do_bfs(), placeholders::_1, s, vis))();
};
return boost::python::object(BFSGenerator(dispatch));
}
void export_bfs()
{
using namespace boost::python;
def("bfs_search", &bfs_search);
def("bfs_search_generator", &bfs_search_generator);
class_<BFSGenerator>("BFSGenerator", no_init)
.def("__iter__", objects::identity_function())
.def("next", &BFSGenerator::next)
.def("__next__", &BFSGenerator::next);
}
......@@ -11,6 +11,7 @@
#include <boost/python.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/undirected_dfs.hpp>
#include <boost/coroutine/all.hpp>
#include "graph.hh"
#include "graph_selectors.hh"
......@@ -89,9 +90,9 @@ private:
struct do_dfs
{
template <class Graph, class VertexIndexMap>
template <class Graph, class VertexIndexMap, class Visitor>
void operator()(Graph& g, VertexIndexMap vertex_index, size_t s,
DFSVisitorWrapper vis) const
Visitor vis) const
{
typename property_map_type::apply<default_color_type,
VertexIndexMap>::type
......@@ -108,8 +109,68 @@ void dfs_search(GraphInterface& g, size_t s, python::object vis)
s, DFSVisitorWrapper(g, vis)))();
}
typedef boost::coroutines::asymmetric_coroutine<boost::python::object> coro_t;
class DFSGeneratorVisitor : public dfs_visitor<>
{
public:
DFSGeneratorVisitor(GraphInterface& gi,
coro_t::push_type& yield)
: _gi(gi), _yield(yield) {}
template <class Edge, class Graph>
void tree_edge(const Edge& e, Graph& g)
{
std::shared_ptr<Graph> gp = retrieve_graph_view<Graph>(_gi, g);
_yield(boost::python::object(PythonEdge<Graph>(gp, e)));
}
private:
GraphInterface& _gi;
coro_t::push_type& _yield;
};
class DFSGenerator
{
public:
template <class Dispatch>
DFSGenerator(Dispatch& dispatch)
: _coro(std::make_shared<coro_t::pull_type>(dispatch)),
_iter(begin(*_coro)), _end(end(*_coro)) {}
boost::python::object next()
{
if (_iter == _end)
boost::python::objects::stop_iteration_error();
boost::python::object oe = *_iter;
++_iter;
return oe;
}
private:
std::shared_ptr<coro_t::pull_type> _coro;
coro_t::pull_type::iterator _iter;
coro_t::pull_type::iterator _end;
};
boost::python::object dfs_search_generator(GraphInterface& g, size_t s)
{
auto dispatch = [&](auto& yield)
{
DFSGeneratorVisitor vis(g, yield);
run_action<graph_tool::detail::all_graph_views,mpl::true_>()
(g, std::bind(do_dfs(), placeholders::_1,
g.get_vertex_index(), s, vis))();
};
return boost::python::object(DFSGenerator(dispatch));
}
void export_dfs()
{
using namespace boost::python;
def("dfs_search", &dfs_search);
def("dfs_search_generator", &dfs_search_generator);
class_<DFSGenerator>("DFSGenerator", no_init)
.def("__iter__", objects::identity_function())
.def("next", &DFSGenerator::next)
.def("__next__", &DFSGenerator::next);
}
......@@ -20,6 +20,7 @@
#include <boost/python.hpp>
#include <boost/graph/dijkstra_shortest_paths_no_color_map.hpp>
#include <boost/coroutine/all.hpp>
#include "graph.hh"
#include "graph_selectors.hh"
......@@ -125,45 +126,151 @@ private:
struct do_djk_search
{
template <class Graph, class DistanceMap>
template <class Graph, class DistanceMap, class PredMap, class Visitor>
void operator()(const Graph& g, size_t s, DistanceMap dist,
boost::any pred_map, boost::any aweight,
DJKVisitorWrapper vis, const DJKCmp& cmp, const DJKCmb& cmb,
PredMap pred_map, boost::any aweight,
Visitor vis, const DJKCmp& cmp, const DJKCmb& cmb,
pair<python::object, python::object> range) const
{
typedef typename property_traits<DistanceMap>::value_type dtype_t;