Commit 61421243 authored by Tiago Peixoto's avatar Tiago Peixoto

Refactor run_action<> and implement the more general gt_dispatch<>

parent b57dcbd5
......@@ -106,7 +106,7 @@
.. autoattribute:: vertex_index
.. autoattribute:: edge_index
.. autoattribute:: max_edge_index
.. autoattribute:: edge_index_range
.. automethod:: reindex_edges
.. container:: sec_title
......
......@@ -557,11 +557,9 @@ boost::any do_init_neighbour_sampler(GraphInterface& gi, boost::any oeweights,
struct collect_edge_marginals_dispatch
{
template <class Graph, class Vprop, class MEprop>
void operator()(Graph& g, size_t B, Vprop cb, MEprop p,
std::tuple<boost::any, GraphInterface&> abg) const
template <class Graph, class BGraph, class Vprop, class MEprop>
void operator()(Graph& g, size_t B, Vprop cb, MEprop p, BGraph& bg) const
{
Graph& bg = *any_cast<Graph*>(get<0>(abg));
collect_edge_marginals(B, cb.get_unchecked(num_vertices(bg)), p, g, bg);
}
};
......@@ -578,10 +576,11 @@ void do_collect_edge_marginals(GraphInterface& gi, GraphInterface& gbi,
vmap_t b = any_cast<vmap_t>(ob);
emap_t p = any_cast<emap_t>(op);
run_action<graph_tool::detail::all_graph_views, boost::mpl::true_>()
run_action<all_graph_views, boost::mpl::true_>()
(gi, std::bind<void>(collect_edge_marginals_dispatch(),
std::placeholders::_1, B, b, p,
std::tuple<boost::any, GraphInterface&>(gbi.get_graph_view(), gbi)))();
std::placeholders::_2),
all_graph_views())(gbi.get_graph_view());
}
boost::python::tuple do_bethe_entropy(GraphInterface& gi, size_t B, boost::any op,
......@@ -599,8 +598,8 @@ boost::python::tuple do_bethe_entropy(GraphInterface& gi, size_t B, boost::any o
double H=0, sH=0, Hmf=0, sHmf=0;
run_action<graph_tool::detail::all_graph_views, boost::mpl::true_>()
(gi, std::bind<void>(bethe_entropy(),
std::placeholders::_1, B, p, pv, std::ref(H), std::ref(sH),
std::ref(Hmf), std::ref(sHmf)))();
std::placeholders::_1, B, p, pv, std::ref(H),
std::ref(sH), std::ref(Hmf), std::ref(sHmf)))();
return boost::python::make_tuple(H, sH, Hmf, sHmf);
}
......
......@@ -3110,8 +3110,8 @@ struct init_neighbour_sampler
// Sampling marginal probabilities on the edges
template <class Graph, class Vprop, class MEprop>
void collect_edge_marginals(size_t B, Vprop b, MEprop p, Graph& g, Graph&)
template <class Graph, class BGraph, class Vprop, class MEprop>
void collect_edge_marginals(size_t B, Vprop b, MEprop p, Graph& g, BGraph&)
{
for (auto e : edges_range(g))
{
......
......@@ -29,7 +29,7 @@ pair<double,double>
assortativity_coefficient(GraphInterface& gi,
GraphInterface::deg_t deg)
{
double a, a_err;
double a = 0, a_err = 0;
run_action<>()(gi,std::bind(get_assortativity_coefficient(),
std::placeholders::_1, std::placeholders::_2,
std::ref(a), std::ref(a_err)),
......@@ -42,7 +42,7 @@ pair<double,double>
scalar_assortativity_coefficient(GraphInterface& gi,
GraphInterface::deg_t deg)
{
double a, a_err;
double a = 0, a_err = 0;
run_action<>()(gi, std::bind(get_scalar_assortativity_coefficient(),
std::placeholders::_1, std::placeholders::_2,
std::ref(a), std::ref(a_err)),
......
......@@ -206,7 +206,7 @@ void pack(vector<point_t>& cp, vector<T>& ncp)
struct do_get_cts
{
template <class Graph, class Tree, class PosProp, class BProp, class CMap>
void operator()(Graph& g, Tree* t, PosProp tpos, BProp beta, CMap cts,
void operator()(Graph& g, Tree& t, PosProp tpos, BProp beta, CMap cts,
bool is_tree, size_t max_depth) const
{
vector<size_t> path;
......@@ -222,9 +222,9 @@ struct do_get_cts
path.clear();
if (is_tree)
tree_path(*t, u, v, path, max_depth);
tree_path(t, u, v, path, max_depth);
else
graph_path(*t, u, v, path);
graph_path(t, u, v, path);
cp.clear();
get_control_points(path, tpos, beta[e], cp);
ncp.clear();
......@@ -235,16 +235,6 @@ struct do_get_cts
}
};
struct get_pointers
{
template <class List>
struct apply
{
typedef typename boost::mpl::transform<List,
boost::mpl::quote1<std::add_pointer> >::type type;
};
};
void get_cts(GraphInterface& gi, GraphInterface& tgi, boost::any otpos,
boost::any obeta, boost::any octs, bool is_tree, size_t max_depth)
{
......@@ -258,10 +248,11 @@ void get_cts(GraphInterface& gi, GraphInterface& tgi, boost::any otpos,
eprop_t cts = boost::any_cast<eprop_t>(octs);
beprop_t beta = boost::any_cast<beprop_t>(obeta);
run_action<>()
(gi, std::bind(do_get_cts(), std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, beta, cts, is_tree, max_depth),
get_pointers::apply<graph_tool::detail::always_directed>::type(),
gt_dispatch<>()
(std::bind(do_get_cts(), std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, beta, cts, is_tree, max_depth),
graph_tool::all_graph_views(),
graph_tool::always_directed(),
vertex_scalar_vector_properties())
(tgi.get_graph_view(), otpos);
(gi.get_graph_view(), tgi.get_graph_view(), otpos);
}
......@@ -35,25 +35,15 @@ typedef property_map_type::apply<GraphInterface::edge_t,
GraphInterface::edge_index_map_t>::type
eprop_t;
struct get_pointers
{
template <class List>
struct apply
{
typedef typename boost::mpl::transform<List,
boost::mpl::quote1<std::add_pointer> >::type type;
};
};
boost::python::tuple graph_union(GraphInterface& ugi, GraphInterface& gi,
boost::any avprop)
{
vprop_t vprop = boost::any_cast<vprop_t>(avprop);
eprop_t eprop(gi.get_edge_index());
run_action<graph_tool::detail::always_directed,boost::mpl::true_>()
(ugi, std::bind(graph_tool::graph_union(),
std::placeholders::_1, std::placeholders::_2, vprop, eprop),
get_pointers::apply<graph_tool::detail::always_directed>::type())
(gi.get_graph_view());
gt_dispatch<boost::mpl::true_>()
(std::bind(graph_tool::graph_union(),
std::placeholders::_1, std::placeholders::_2, vprop, eprop),
always_directed(), always_directed())
(ugi.get_graph_view(), gi.get_graph_view());
return boost::python::make_tuple(avprop, boost::any(eprop));
}
......@@ -30,10 +30,9 @@ using namespace boost;
struct graph_union
{
template <class UnionGraph, class Graph, class VertexMap, class EdgeMap>
void operator()(UnionGraph& ug, Graph* gp, VertexMap vmap, EdgeMap emap)
void operator()(UnionGraph& ug, Graph& g, VertexMap vmap, EdgeMap emap)
const
{
Graph& g = *gp;
for (auto v : vertices_range(g))
{
if (vmap[v] < 0)
......@@ -61,10 +60,9 @@ struct property_union
{
template <class UnionGraph, class Graph, class VertexMap, class EdgeMap,
class UnionProp>
void operator()(UnionGraph& ug, Graph* gp, VertexMap vmap, EdgeMap emap,
void operator()(UnionGraph& ug, Graph& g, VertexMap vmap, EdgeMap emap,
UnionProp uprop, boost::any aprop) const
{
Graph& g = *gp;
auto prop = any_cast<typename UnionProp::checked_t>(aprop);
dispatch(ug, g, vmap, emap, uprop, prop,
std::is_same<typename property_traits<UnionProp>::key_type,
......
......@@ -37,16 +37,6 @@ typedef property_map_type::apply<GraphInterface::edge_t,
GraphInterface::edge_index_map_t>::type
eprop_t;
struct get_pointers
{
template <class List>
struct apply
{
typedef typename boost::mpl::transform<List,
boost::mpl::quote1<std::add_pointer> >::type type;
};
};
void edge_property_union(GraphInterface& ugi, GraphInterface& gi,
boost::any p_vprop, boost::any p_eprop,
boost::any uprop, boost::any prop)
......@@ -58,7 +48,6 @@ void edge_property_union(GraphInterface& ugi, GraphInterface& gi,
(ugi, std::bind(graph_tool::property_union(),
std::placeholders::_1, std::placeholders::_2, vprop, eprop,
std::placeholders::_3, prop),
get_pointers::apply<graph_tool::detail::always_directed>::type(),
writable_edge_properties())
always_directed(), writable_edge_properties())
(gi.get_graph_view(), uprop);
}
......@@ -35,16 +35,6 @@ typedef property_map_type::apply<GraphInterface::edge_t,
GraphInterface::edge_index_map_t>::type
eprop_t;
struct get_pointers
{
template <class List>
struct apply
{
typedef typename boost::mpl::transform<List,
boost::mpl::quote1<std::add_pointer> >::type type;
};
};
void vertex_property_union(GraphInterface& ugi, GraphInterface& gi,
boost::any p_vprop, boost::any p_eprop,
boost::any uprop, boost::any prop)
......@@ -52,11 +42,11 @@ void vertex_property_union(GraphInterface& ugi, GraphInterface& gi,
vprop_t vprop = any_cast<vprop_t>(p_vprop);
eprop_t eprop = any_cast<eprop_t>(p_eprop);
run_action<graph_tool::detail::always_directed>()
(ugi, std::bind(graph_tool::property_union(),
std::placeholders::_1, std::placeholders::_2, vprop, eprop,
std::placeholders::_3, prop),
get_pointers::apply<graph_tool::detail::always_directed>::type(),
gt_dispatch<>()
(std::bind(graph_tool::property_union(), std::placeholders::_1,
std::placeholders::_2, vprop, eprop, std::placeholders::_3,
prop),
always_directed(), always_directed(),
writable_vertex_properties())
(gi.get_graph_view(), uprop);
(ugi.get_graph_view(), gi.get_graph_view(), uprop);
}
......@@ -41,11 +41,9 @@ string name_demangle(string name)
}
// Whenever no implementation is called, the following exception is thrown
graph_tool::ActionNotFound::ActionNotFound(const boost::any& graph_view,
const type_info& action,
graph_tool::ActionNotFound::ActionNotFound(const type_info& action,
const vector<const type_info*>& args)
: GraphException(""), _graph_view(graph_view),
_action(action), _args(args) {}
: GraphException(""), _action(action), _args(args) {}
const char * graph_tool::ActionNotFound::what () const throw ()
{
......@@ -57,7 +55,6 @@ const char * graph_tool::ActionNotFound::what () const throw ()
"instructions at " PACKAGE_BUGREPORT ". What follows is debug "
"information.\n\n";
error += "Graph view: " + name_demangle(_graph_view.type().name()) + "\n\n";
error += "Action: " + name_demangle(_action.name()) + "\n\n";
for (size_t i = 0; i < _args.size(); ++i)
{
......@@ -80,10 +77,10 @@ boost::any check_reverse(const Graph& g, bool reverse, GraphInterface& gi)
reverse_graph_t;
reverse_graph_t rg(g);
return retrieve_graph_view(gi, rg).get();
return std::ref(*retrieve_graph_view(gi, rg).get());
}
return boost::any(const_cast<Graph*>(&g));
return boost::any(std::ref(const_cast<Graph&>(g)));
};
// this will check whether a graph is directed and return the proper view
......@@ -99,7 +96,7 @@ boost::any check_directed(const Graph &g, bool reverse, bool directed,
typedef UndirectedAdaptor<Graph> ug_t;
ug_t ug(g);
return retrieve_graph_view(gi, ug).get();
return std::ref(*retrieve_graph_view(gi, ug).get());
};
// this will check whether a graph is filtered and return the proper view
......
......@@ -114,12 +114,11 @@ namespace graph_tool
class ActionNotFound: public GraphException
{
public:
ActionNotFound(const boost::any& graph_view, const std::type_info& action,
ActionNotFound(const std::type_info& action,
const vector<const std::type_info*>& args);
virtual const char * what () const throw ();
virtual ~ActionNotFound() throw () {}
private:
boost::any _graph_view;
const std::type_info& _action;
vector<const std::type_info*> _args;
};
......@@ -365,119 +364,147 @@ BOOST_MPL_ASSERT_RELATION(n_views::value, == , boost::mpl::int_<6>::value);
BOOST_MPL_ASSERT_RELATION(n_views::value, == , boost::mpl::int_<3>::value);
#endif
// run_action() implementation
// ===========================
// run_action() and gt_dispatch() implementation
// =============================================
// wrap action to be called, to deal with property maps, i.e., return version
// with no bounds checking.
template <class Action, class Wrap>
struct action_wrap
{
action_wrap(Action a, GraphInterface& g, size_t max_v, size_t max_e)
: _a(a), _g(g), _max_v(max_v), _max_e(max_e) {}
action_wrap(Action a) : _a(a) {}
template <class Type>
boost::checked_vector_property_map<Type,GraphInterface::vertex_index_map_t>&
uncheck(boost::checked_vector_property_map
<Type,GraphInterface::vertex_index_map_t>& a, boost::mpl::true_) const
auto& uncheck(boost::checked_vector_property_map
<Type,GraphInterface::vertex_index_map_t>& a, boost::mpl::true_) const
{
return a;
}
template <class Type>
boost::unchecked_vector_property_map<Type,GraphInterface::vertex_index_map_t>
uncheck(boost::checked_vector_property_map
<Type,GraphInterface::vertex_index_map_t> a, boost::mpl::false_) const
auto uncheck(boost::checked_vector_property_map
<Type,GraphInterface::vertex_index_map_t>& a, boost::mpl::false_) const
{
return a.get_unchecked(_max_v);
return a.get_unchecked();
}
template <class Type>
boost::checked_vector_property_map<Type,GraphInterface::edge_index_map_t>&
uncheck(boost::checked_vector_property_map
<Type,GraphInterface::edge_index_map_t>& a, boost::mpl::true_) const
auto& uncheck(boost::checked_vector_property_map
<Type,GraphInterface::edge_index_map_t>& a, boost::mpl::true_) const
{
return a;
}
template <class Type>
boost::unchecked_vector_property_map<Type,GraphInterface::edge_index_map_t>
uncheck(boost::checked_vector_property_map
<Type,GraphInterface::edge_index_map_t> a, boost::mpl::false_) const
auto uncheck(boost::checked_vector_property_map
<Type,GraphInterface::edge_index_map_t>& a, boost::mpl::false_) const
{
return a.get_unchecked(_max_e);
return a.get_unchecked();
}
template <class Type>
scalarS<typename Type::unchecked_t>
uncheck(scalarS<Type> a, boost::mpl::false_) const
auto uncheck(scalarS<Type>& a, boost::mpl::false_) const
{
return scalarS<typename Type::unchecked_t>(uncheck(a._pmap,
boost::mpl::false_()));
auto pmap = uncheck(a._pmap, boost::mpl::false_());
return scalarS<decltype(pmap)>(pmap);
}
//no op
template <class Type, class DoWrap>
Type& uncheck(Type& a, DoWrap) const { return a; }
Type& uncheck(Type&& a, DoWrap) const { return a; }
void operator()() const {};
template <class T1> void operator()(T1* a1) const
{ _a(*a1); }
template <class Type>
auto& deference(Type* a) const
{
typedef typename std::remove_const<Type>::type type_t;
typedef typename boost::mpl::find<detail::all_graph_views, type_t>::type iter_t;
typedef typename boost::mpl::end<detail::all_graph_views>::type end_t;
return deference_dispatch(a, typename std::is_same<iter_t, end_t>::type());
}
template <class Type>
auto& deference_dispatch(Type*& a, std::true_type) const
{
return a;
}
template <class T1, class... Ts>
void operator()(T1* a1, Ts&&... as) const
template <class Type>
Type& deference_dispatch(Type* a, std::false_type) const
{
_a(*a1, uncheck(std::forward<Ts>(as), Wrap())...);
return *a;
}
template <class Type>
Type& deference(Type&& a) const
{
return a;
}
template <class... Ts>
void operator()(Ts&&... as) const
{
_a(deference(uncheck(std::forward<Ts>(as), Wrap()))...);
}
Action _a;
reference_wrapper<GraphInterface> _g;
size_t _max_v, _max_e;
};
// this functor encapsulates another functor Action, which takes a pointer to a
// graph view as first argument
template <class Action, class GraphViews, class Wrap, class... TRS>
struct graph_action
// this takes a functor and type ranges and iterates through the type
// combinations when called with boost::any parameters, and calls the correct
// function
template <class Action, class Wrap, class... TRS>
struct action_dispatch
{
struct graph_view_pointers:
boost::mpl::transform<GraphViews, boost::mpl::quote1<add_pointer> >::type {};
graph_action(GraphInterface& g, Action a)
: _g(g), _a(a, g, num_vertices(*g._mg),
max(g._mg->get_edge_index_range(), size_t(1))) {}
action_dispatch(Action a) : _a(a) {}
template <class... Args>
void operator()(Args&&... args) const
{
boost::any gview = _g.get_graph_view();
bool found = boost::mpl::nested_for_each<graph_view_pointers,TRS...>
(_a, gview, std::forward<Args>(args)...);
bool found =
boost::mpl::nested_for_each<TRS...>(_a, std::forward<Args>(args)...);
if (!found)
{
vector<const std::type_info*> args_t = {(&(args).type())...};
throw ActionNotFound(gview, typeid(Action), args_t);
throw ActionNotFound(typeid(Action), args_t);
}
}
const GraphInterface &_g;
action_wrap<Action, Wrap> _a;
};
} // details namespace
} // details namespace
// all definitions of run_action with different arity
// dispatch "Action" across all type combinations
template <class GraphViews = detail::all_graph_views, class Wrap = boost::mpl::false_>
struct run_action
{
template <class Action, class... TRS>
detail::graph_action<Action,GraphViews,Wrap,TRS...>
operator()(GraphInterface &g, Action&& a, TRS...)
auto operator()(GraphInterface& gi, Action a, TRS...)
{
return detail::graph_action<Action,GraphViews,Wrap,TRS...>(g, std::forward<Action>(a));
auto dispatch = detail::action_dispatch<Action,Wrap,GraphViews,TRS...>(a);
auto wrap = [dispatch, &gi](auto&&... args) { dispatch(gi.get_graph_view(), args...); };
return wrap;
}
};
template <class Wrap = boost::mpl::false_>
struct gt_dispatch
{
template <class Action, class... TRS>
auto operator()(Action a, TRS...)
{
return detail::action_dispatch<Action,Wrap,TRS...>(a);
}
};
typedef detail::all_graph_views all_graph_views;
typedef detail::always_directed always_directed;
typedef detail::never_directed never_directed;
typedef detail::always_reversed always_reversed;
typedef detail::never_reversed never_reversed;
typedef detail::always_directed_never_reversed always_directed_never_reversed;
typedef detail::never_filtered never_filtered;
// returns true if graph filtering was enabled at compile time
bool graph_filtering_enabled();
......
......@@ -28,18 +28,14 @@ using namespace std;
using namespace boost;
using namespace graph_tool;
struct graph_views:
boost::mpl::transform<graph_tool::detail::all_graph_views,
boost::mpl::quote1<std::add_pointer> >::type {};
void GraphInterface::copy_vertex_property(const GraphInterface& src,
boost::any prop_src,
boost::any prop_tgt)
{
run_action<>()
(*this, std::bind(copy_property<vertex_selector,vertex_properties>(),
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, prop_src),
graph_views(), writable_vertex_properties())
(src.get_graph_view(), prop_tgt);
gt_dispatch<>()
(std::bind(copy_property<vertex_selector,vertex_properties>(),
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, prop_src),
all_graph_views(), all_graph_views(), writable_vertex_properties())
(this->get_graph_view(), src.get_graph_view(), prop_tgt);
}
......@@ -36,7 +36,7 @@ template <class IteratorSel, class PropertyMaps>
struct copy_property
{
template <class GraphTgt, class GraphSrc, class PropertyTgt>
void operator()(const GraphTgt& tgt, const GraphSrc* src,
void operator()(const GraphTgt& tgt, const GraphSrc& src,
PropertyTgt dst_map, boost::any prop_src) const
{
try
......@@ -56,7 +56,7 @@ struct copy_property
}
template <class GraphTgt, class GraphSrc, class PropertyTgt, class PropertySrc>
void dispatch(const GraphTgt& tgt, const GraphSrc* src,
void dispatch(const GraphTgt& tgt, const GraphSrc& src,
PropertyTgt dst_map, PropertySrc src_map) const
{
try
......@@ -64,7 +64,7 @@ struct copy_property
typename IteratorSel::template apply<GraphSrc>::type vs, vs_end;
typename IteratorSel::template apply<GraphTgt>::type vt, vt_end;
tie(vt, vt_end) = IteratorSel::range(tgt);
tie(vs, vs_end) = IteratorSel::range(*src);
tie(vs, vs_end) = IteratorSel::range(src);
for (; vs != vs_end; ++vs)
{
put(dst_map, *vt++, get(src_map, *vs));
......
......@@ -28,18 +28,15 @@ using namespace std;
using namespace boost;
using namespace graph_tool;
struct graph_views:
boost::mpl::transform<graph_tool::detail::all_graph_views,
boost::mpl::quote1<std::add_pointer> >::type {};
void GraphInterface::copy_edge_property(const GraphInterface& src,
boost::any prop_src,
boost::any prop_tgt)
{
run_action<>()
(*this, std::bind(copy_property<edge_selector,edge_properties>(),
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, prop_src),
graph_views(), writable_edge_properties())
(src.get_graph_view(), prop_tgt);
gt_dispatch<>()
(std::bind(copy_property<edge_selector,edge_properties>(),
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, prop_src),
all_graph_views(), all_graph_views(),
writable_edge_properties())
(this->get_graph_view(), src.get_graph_view(), prop_tgt);
}
......@@ -58,8 +58,7 @@ struct export_vertex_property_map
boost::python::class_<pmap_t> pclass(class_name.c_str(),
boost::python::no_init);
pclass
.def("__hash__", &pmap_t::get_hash)
pclass.def("__hash__", &pmap_t::get_hash)
.def("value_type", &pmap_t::get_type)
.def("get_map", &pmap_t::get_map)
.def("get_dynamic_map", &pmap_t::get_dynamic_map)
......
......@@ -84,7 +84,7 @@ struct do_propagate_pos
{
template <class Graph, class CoarseGraph, class VertexMap, class PosMap,
class RNG>
void operator()(Graph& g, CoarseGraph* cg, VertexMap vmap,
void operator()(Graph& g, CoarseGraph& cg, VertexMap vmap,
boost::any acvmap, PosMap pos, boost::any acpos,
double delta, RNG& rng) const
{
......@@ -99,7 +99,7 @@ struct do_propagate_pos