From 7a401052ca65aff860da048d8145f0f61fcbf87c Mon Sep 17 00:00:00 2001 From: Tiago de Paula Peixoto Date: Tue, 2 Jul 2013 17:50:32 +0200 Subject: [PATCH] Implement weighted degree property maps and weighted degree selectors --- src/graph/graph.hh | 2 +- src/graph/graph_bind.cc | 3 +- src/graph/graph_copy.cc | 1 + src/graph/graph_python_interface.cc | 42 +++++++--- src/graph/graph_selectors.hh | 122 ++++++++++++++++++++++------ src/graph_tool/__init__.py | 15 ++-- 6 files changed, 141 insertions(+), 44 deletions(-) diff --git a/src/graph/graph.hh b/src/graph/graph.hh index 07ca3256..2d6d5dd7 100644 --- a/src/graph/graph.hh +++ b/src/graph/graph.hh @@ -111,7 +111,7 @@ public: // // python interface // - python::object DegreeMap(string deg) const; + python::object DegreeMap(string deg, boost::any weight) const; // used for graph properties graph_property_tag GetDescriptor() const { return graph_property_tag(); } diff --git a/src/graph/graph_bind.cc b/src/graph/graph_bind.cc index 89cdc602..f1a4b1de 100644 --- a/src/graph/graph_bind.cc +++ b/src/graph/graph_bind.cc @@ -366,7 +366,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_core) mpl::for_each::type>(export_vector_types()); class_("GraphInterface", init<>()) - .def(init()) + .def(init()) .def("GetNumberOfVertices", &GraphInterface::GetNumberOfVertices) .def("GetNumberOfEdges", &GraphInterface::GetNumberOfEdges) .def("SetDirected", &GraphInterface::SetDirected) @@ -445,4 +445,3 @@ BOOST_PYTHON_MODULE(libgraph_tool_core) def("get_graph_type", &get_graph_type); } - diff --git a/src/graph/graph_copy.cc b/src/graph/graph_copy.cc index deb9a5a2..d5e2d7b5 100644 --- a/src/graph/graph_copy.cc +++ b/src/graph/graph_copy.cc @@ -158,6 +158,7 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref, ref(python::extract(oeprops[i][1])()))); } + boost::any avorder = python::extract(vorder); run_action<>() (const_cast(gi), bind(do_graph_copy(), _1, ref(*_mg), diff --git a/src/graph/graph_python_interface.cc b/src/graph/graph_python_interface.cc index a0011ebc..3693c3e2 100644 --- a/src/graph/graph_python_interface.cc +++ b/src/graph/graph_python_interface.cc @@ -230,9 +230,19 @@ void remove_edge(GraphInterface& gi, const python::object& e) struct get_degree_map { - template - void operator()(const Graph& g, DegreeMap deg_map, DegS deg) const + template + void operator()(const Graph& g, python::object& odeg_map, DegS deg, Weight weight) const { + typedef typename detail::get_weight_type::type weight_t; + typedef typename mpl::if_, int32_t, weight_t>::type deg_t; + + typedef typename property_map_type::apply::type + map_t; + + map_t cdeg_map(get(vertex_index, g)); + typename map_t::unchecked_t deg_map = cdeg_map.get_unchecked(num_vertices(g)); + int i, N = num_vertices(g); #pragma omp parallel for default(shared) private(i) schedule(dynamic) for (i = 0; i < N; ++i) @@ -240,33 +250,39 @@ struct get_degree_map typename graph_traits::vertex_descriptor v = vertex(i, g); if (v == graph_traits::null_vertex()) continue; - deg_map[v] = deg(v, g); + deg_map[v] = deg(v, g, weight); } + + odeg_map = python::object(PythonPropertyMap(cdeg_map)); } }; -python::object GraphInterface::DegreeMap(string deg) const +python::object GraphInterface::DegreeMap(string deg, boost::any weight) const { - typedef property_map_type::apply::type - map_t; - map_t deg_map(_vertex_index); - deg_map.reserve(num_vertices(*_mg)); + python::object deg_map; + + typedef typename mpl::push_back::type weight_t; + if (weight.empty()) + weight = detail::no_weightS(); if (deg == "in") run_action<>()(const_cast(*this), bind(get_degree_map(), _1, - deg_map, in_degreeS()))(); + ref(deg_map), in_degreeS(), _2), weight_t()) + (weight); else if (deg == "out") run_action<>()(const_cast(*this), bind(get_degree_map(), _1, - deg_map, out_degreeS()))(); + ref(deg_map), out_degreeS(), _2), weight_t()) + (weight); else if (deg == "total") run_action<>()(const_cast(*this), bind(get_degree_map(), _1, - deg_map, total_degreeS()))(); - return python::object(PythonPropertyMap(deg_map)); + ref(deg_map), total_degreeS(), _2), weight_t()) + (weight); + return deg_map; } // diff --git a/src/graph/graph_selectors.hh b/src/graph/graph_selectors.hh index 305835f0..d6d3f831 100644 --- a/src/graph/graph_selectors.hh +++ b/src/graph/graph_selectors.hh @@ -42,78 +42,154 @@ namespace graph_tool // This file also contains selectors for in_edge iterators of graphs, which // return an empty range for undirected graphs -struct total_degreeS +namespace detail +{ + struct no_weightS {}; + + template + struct get_weight_type + { + typedef typename property_traits::value_type type; + }; + + template <> + struct get_weight_type + { + typedef size_t type; + }; +} + +struct in_degreeS { typedef size_t value_type; - total_degreeS() {} + in_degreeS() {} + template size_t operator()(const Vertex& v, const Graph &g) const + { + return in_degreeS::operator()(v, g, detail::no_weightS()); + } + + template + typename detail::get_weight_type::type + operator()(const Vertex& v, const Graph &g, Weight weight) const { using namespace boost; typedef typename is_convertible ::directed_category, directed_tag>::type is_directed; - return get_total_degree(v,g,is_directed()); + return get_in_degree(v, g, is_directed(), weight); } template - size_t get_total_degree(const Vertex& v, const Graph &g, boost::true_type) + size_t get_in_degree(const Vertex& v, const Graph &g, boost::true_type, + detail::no_weightS) const { - return in_degree(v,g)+out_degree(v,g); + return in_degree(v, g); } - template - size_t get_total_degree(const Vertex& v, const Graph &g, boost::false_type) + template + typename detail::get_weight_type::type + get_in_degree(const Vertex& v, const Graph &g, boost::true_type, + Weight weight) + const + { + typename property_traits::value_type d = 0; + typename graph_traits::in_edge_iterator e, e_end; + for (tie(e, e_end) = in_edges(v, g); e != e_end; ++e) + d += get(weight, *e); + return d; + } + + template + size_t get_in_degree(const Vertex&, const Graph &, boost::false_type, Weight) const { - return out_degree(v,g); + return 0; } }; -struct in_degreeS +struct out_degreeS { typedef size_t value_type; - in_degreeS() {} + out_degreeS() {} + template size_t operator()(const Vertex& v, const Graph &g) const { - using namespace boost; - typedef typename is_convertible - ::directed_category, - directed_tag>::type is_directed; - return get_in_degree(v,g,is_directed()); + return out_degreeS::operator()(v, g, detail::no_weightS()); } - template - size_t get_in_degree(const Vertex& v, const Graph &g, boost::true_type) + template + typename detail::get_weight_type::type + operator()(const Vertex& v, const Graph &g, Weight weight) const + { + return get_out_degree(v, g, weight); + } + + template + typename detail::get_weight_type::type + get_out_degree(const Vertex& v, const Graph &g, Weight weight) const { - return in_degree(v,g); + typename property_traits::value_type d = 0; + typename graph_traits::out_edge_iterator e, e_end; + for (tie(e, e_end) = out_edges(v, g); e != e_end; ++e) + d += get(weight, *e); + return d; } template - size_t get_in_degree(const Vertex&, const Graph &, boost::false_type) + size_t get_out_degree(const Vertex& v, const Graph &g, detail::no_weightS) const { - return 0; + return out_degree(v, g); } }; -struct out_degreeS +struct total_degreeS { typedef size_t value_type; - out_degreeS() {} + total_degreeS() {} template size_t operator()(const Vertex& v, const Graph &g) const { - return out_degree(v,g); + return total_degreeS::operator()(v, g, detail::no_weightS()); + } + + template + typename detail::get_weight_type::type + operator()(const Vertex& v, const Graph &g, Weight weight) const + { + using namespace boost; + typedef typename is_convertible + ::directed_category, + directed_tag>::type is_directed; + return get_total_degree(v, g, is_directed(), weight); + } + + template + typename detail::get_weight_type::type + get_total_degree(const Vertex& v, const Graph &g, boost::true_type, Weight weight) + const + { + return in_degreeS()(v, g, weight) + out_degreeS()(v, g, weight); + } + + template + typename detail::get_weight_type::type + get_total_degree(const Vertex& v, const Graph &g, boost::false_type, Weight weight) + const + { + return out_degreeS()(v, g, weight); } }; + template struct scalarS { diff --git a/src/graph_tool/__init__.py b/src/graph_tool/__init__.py index c1e3beeb..f92de548 100644 --- a/src/graph_tool/__init__.py +++ b/src/graph_tool/__init__.py @@ -1068,7 +1068,8 @@ class Graph(object): vorder.fa = numpy.arange(g.num_vertices()) # The actual copying of the graph and property maps - self.__graph = libcore.GraphInterface(g.__graph, False, vprops, eprops) + self.__graph = libcore.GraphInterface(g.__graph, False, vprops, eprops, + _prop("v", g, vorder)) # Put the copied properties in the internal dictionary for k, v in g.vertex_properties.items(): @@ -1583,10 +1584,13 @@ class Graph(object): # degree property map @_limit_args({"deg": ["in", "out", "total"]}) - def degree_property_map(self, deg): + def degree_property_map(self, deg, weight=None): """Create and return a vertex property map containing the degree type - given by ``deg``.""" - return PropertyMap(self.__graph.DegreeMap(deg), self, "v") + given by ``deg``. If provided, ``weight`` should be an edge + :class:`~graph_tool.PropertyMap` containing the edge weights which + should be summed.""" + pmap = self.__graph.DegreeMap(deg, _prop("e", self, weight)) + return PropertyMap(pmap, self, "v") # I/O operations # ============== @@ -2097,7 +2101,8 @@ class GraphView(Graph): Graph.__init__(self) # copy graph reference self._Graph__graph = libcore.GraphInterface(g._Graph__graph, True, - [], []) + [], [], + _prop("v", g, g.vertex_index)) for k, v in g.properties.items(): self.properties[k] = self.own_property(v) -- GitLab