Commit 7a401052 authored by Tiago Peixoto's avatar Tiago Peixoto

Implement weighted degree property maps and weighted degree selectors

parent 0c4b511c
...@@ -111,7 +111,7 @@ public: ...@@ -111,7 +111,7 @@ public:
// //
// python interface // python interface
// //
python::object DegreeMap(string deg) const; python::object DegreeMap(string deg, boost::any weight) const;
// used for graph properties // used for graph properties
graph_property_tag GetDescriptor() const { return graph_property_tag(); } graph_property_tag GetDescriptor() const { return graph_property_tag(); }
......
...@@ -366,7 +366,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_core) ...@@ -366,7 +366,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
mpl::for_each<mpl::push_back<scalar_types,string>::type>(export_vector_types()); mpl::for_each<mpl::push_back<scalar_types,string>::type>(export_vector_types());
class_<GraphInterface>("GraphInterface", init<>()) class_<GraphInterface>("GraphInterface", init<>())
.def(init<GraphInterface,bool,python::object,python::object>()) .def(init<GraphInterface,bool,python::object,python::object,python::object>())
.def("GetNumberOfVertices", &GraphInterface::GetNumberOfVertices) .def("GetNumberOfVertices", &GraphInterface::GetNumberOfVertices)
.def("GetNumberOfEdges", &GraphInterface::GetNumberOfEdges) .def("GetNumberOfEdges", &GraphInterface::GetNumberOfEdges)
.def("SetDirected", &GraphInterface::SetDirected) .def("SetDirected", &GraphInterface::SetDirected)
...@@ -445,4 +445,3 @@ BOOST_PYTHON_MODULE(libgraph_tool_core) ...@@ -445,4 +445,3 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
def("get_graph_type", &get_graph_type); def("get_graph_type", &get_graph_type);
} }
...@@ -158,6 +158,7 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref, ...@@ -158,6 +158,7 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
ref(python::extract<boost::any&>(oeprops[i][1])()))); ref(python::extract<boost::any&>(oeprops[i][1])())));
} }
boost::any avorder = python::extract<boost::any>(vorder);
run_action<>() run_action<>()
(const_cast<GraphInterface&>(gi), (const_cast<GraphInterface&>(gi),
bind<void>(do_graph_copy(), _1, ref(*_mg), bind<void>(do_graph_copy(), _1, ref(*_mg),
......
...@@ -230,9 +230,19 @@ void remove_edge(GraphInterface& gi, const python::object& e) ...@@ -230,9 +230,19 @@ void remove_edge(GraphInterface& gi, const python::object& e)
struct get_degree_map struct get_degree_map
{ {
template <class Graph, class DegreeMap, class DegS> template <class Graph, class DegS, class Weight>
void operator()(const Graph& g, DegreeMap deg_map, DegS deg) const void operator()(const Graph& g, python::object& odeg_map, DegS deg, Weight weight) const
{ {
typedef typename detail::get_weight_type<Weight>::type weight_t;
typedef typename mpl::if_<is_same<weight_t, size_t>, int32_t, weight_t>::type deg_t;
typedef typename property_map_type::apply<deg_t,
GraphInterface::vertex_index_map_t>::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); int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) schedule(dynamic) #pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i) for (i = 0; i < N; ++i)
...@@ -240,33 +250,39 @@ struct get_degree_map ...@@ -240,33 +250,39 @@ struct get_degree_map
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g); typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex()) if (v == graph_traits<Graph>::null_vertex())
continue; continue;
deg_map[v] = deg(v, g); deg_map[v] = deg(v, g, weight);
} }
odeg_map = python::object(PythonPropertyMap<map_t>(cdeg_map));
} }
}; };
python::object GraphInterface::DegreeMap(string deg) const python::object GraphInterface::DegreeMap(string deg, boost::any weight) const
{ {
typedef property_map_type::apply<double,
GraphInterface::vertex_index_map_t>::type
map_t;
map_t deg_map(_vertex_index); python::object deg_map;
deg_map.reserve(num_vertices(*_mg));
typedef typename mpl::push_back<edge_scalar_properties,
detail::no_weightS>::type weight_t;
if (weight.empty())
weight = detail::no_weightS();
if (deg == "in") if (deg == "in")
run_action<>()(const_cast<GraphInterface&>(*this), run_action<>()(const_cast<GraphInterface&>(*this),
bind<void>(get_degree_map(), _1, bind<void>(get_degree_map(), _1,
deg_map, in_degreeS()))(); ref(deg_map), in_degreeS(), _2), weight_t())
(weight);
else if (deg == "out") else if (deg == "out")
run_action<>()(const_cast<GraphInterface&>(*this), run_action<>()(const_cast<GraphInterface&>(*this),
bind<void>(get_degree_map(), _1, bind<void>(get_degree_map(), _1,
deg_map, out_degreeS()))(); ref(deg_map), out_degreeS(), _2), weight_t())
(weight);
else if (deg == "total") else if (deg == "total")
run_action<>()(const_cast<GraphInterface&>(*this), run_action<>()(const_cast<GraphInterface&>(*this),
bind<void>(get_degree_map(), _1, bind<void>(get_degree_map(), _1,
deg_map, total_degreeS()))(); ref(deg_map), total_degreeS(), _2), weight_t())
return python::object(PythonPropertyMap<map_t>(deg_map)); (weight);
return deg_map;
} }
// //
......
...@@ -42,78 +42,154 @@ namespace graph_tool ...@@ -42,78 +42,154 @@ namespace graph_tool
// This file also contains selectors for in_edge iterators of graphs, which // This file also contains selectors for in_edge iterators of graphs, which
// return an empty range for undirected graphs // return an empty range for undirected graphs
struct total_degreeS namespace detail
{
struct no_weightS {};
template <class Weight>
struct get_weight_type
{
typedef typename property_traits<Weight>::value_type type;
};
template <>
struct get_weight_type<no_weightS>
{
typedef size_t type;
};
}
struct in_degreeS
{ {
typedef size_t value_type; typedef size_t value_type;
total_degreeS() {} in_degreeS() {}
template <class Graph, class Vertex> template <class Graph, class Vertex>
size_t operator()(const Vertex& v, const Graph &g) const size_t operator()(const Vertex& v, const Graph &g) const
{
return in_degreeS::operator()(v, g, detail::no_weightS());
}
template <class Graph, class Vertex, class Weight>
typename detail::get_weight_type<Weight>::type
operator()(const Vertex& v, const Graph &g, Weight weight) const
{ {
using namespace boost; using namespace boost;
typedef typename is_convertible typedef typename is_convertible
<typename graph_traits<Graph>::directed_category, <typename graph_traits<Graph>::directed_category,
directed_tag>::type is_directed; directed_tag>::type is_directed;
return get_total_degree(v,g,is_directed()); return get_in_degree(v, g, is_directed(), weight);
} }
template <class Graph, class Vertex> template <class Graph, class Vertex>
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 const
{ {
return in_degree(v,g)+out_degree(v,g); return in_degree(v, g);
} }
template <class Graph, class Vertex> template <class Graph, class Vertex, class Weight>
size_t get_total_degree(const Vertex& v, const Graph &g, boost::false_type) typename detail::get_weight_type<Weight>::type
get_in_degree(const Vertex& v, const Graph &g, boost::true_type,
Weight weight)
const
{
typename property_traits<Weight>::value_type d = 0;
typename graph_traits<Graph>::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 <class Graph, class Vertex, class Weight>
size_t get_in_degree(const Vertex&, const Graph &, boost::false_type, Weight)
const const
{ {
return out_degree(v,g); return 0;
} }
}; };
struct in_degreeS struct out_degreeS
{ {
typedef size_t value_type; typedef size_t value_type;
in_degreeS() {} out_degreeS() {}
template <class Graph, class Vertex> template <class Graph, class Vertex>
size_t operator()(const Vertex& v, const Graph &g) const size_t operator()(const Vertex& v, const Graph &g) const
{ {
using namespace boost; return out_degreeS::operator()(v, g, detail::no_weightS());
typedef typename is_convertible
<typename graph_traits<Graph>::directed_category,
directed_tag>::type is_directed;
return get_in_degree(v,g,is_directed());
} }
template <class Graph, class Vertex> template <class Graph, class Vertex, class Weight>
size_t get_in_degree(const Vertex& v, const Graph &g, boost::true_type) typename detail::get_weight_type<Weight>::type
operator()(const Vertex& v, const Graph &g, Weight weight) const
{
return get_out_degree(v, g, weight);
}
template <class Graph, class Vertex, class Weight>
typename detail::get_weight_type<Weight>::type
get_out_degree(const Vertex& v, const Graph &g, Weight weight)
const const
{ {
return in_degree(v,g); typename property_traits<Weight>::value_type d = 0;
typename graph_traits<Graph>::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 <class Graph, class Vertex> template <class Graph, class Vertex>
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 const
{ {
return 0; return out_degree(v, g);
} }
}; };
struct out_degreeS struct total_degreeS
{ {
typedef size_t value_type; typedef size_t value_type;
out_degreeS() {} total_degreeS() {}
template <class Graph, class Vertex> template <class Graph, class Vertex>
size_t operator()(const Vertex& v, const Graph &g) const 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 <class Graph, class Vertex, class Weight>
typename detail::get_weight_type<Weight>::type
operator()(const Vertex& v, const Graph &g, Weight weight) const
{
using namespace boost;
typedef typename is_convertible
<typename graph_traits<Graph>::directed_category,
directed_tag>::type is_directed;
return get_total_degree(v, g, is_directed(), weight);
}
template <class Graph, class Vertex, class Weight>
typename detail::get_weight_type<Weight>::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 <class Graph, class Vertex, class Weight>
typename detail::get_weight_type<Weight>::type
get_total_degree(const Vertex& v, const Graph &g, boost::false_type, Weight weight)
const
{
return out_degreeS()(v, g, weight);
} }
}; };
template <class PropertyMap> template <class PropertyMap>
struct scalarS struct scalarS
{ {
......
...@@ -1068,7 +1068,8 @@ class Graph(object): ...@@ -1068,7 +1068,8 @@ class Graph(object):
vorder.fa = numpy.arange(g.num_vertices()) vorder.fa = numpy.arange(g.num_vertices())
# The actual copying of the graph and property maps # 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 # Put the copied properties in the internal dictionary
for k, v in g.vertex_properties.items(): for k, v in g.vertex_properties.items():
...@@ -1583,10 +1584,13 @@ class Graph(object): ...@@ -1583,10 +1584,13 @@ class Graph(object):
# degree property map # degree property map
@_limit_args({"deg": ["in", "out", "total"]}) @_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 """Create and return a vertex property map containing the degree type
given by ``deg``.""" given by ``deg``. If provided, ``weight`` should be an edge
return PropertyMap(self.__graph.DegreeMap(deg), self, "v") :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 # I/O operations
# ============== # ==============
...@@ -2097,7 +2101,8 @@ class GraphView(Graph): ...@@ -2097,7 +2101,8 @@ class GraphView(Graph):
Graph.__init__(self) Graph.__init__(self)
# copy graph reference # copy graph reference
self._Graph__graph = libcore.GraphInterface(g._Graph__graph, True, self._Graph__graph = libcore.GraphInterface(g._Graph__graph, True,
[], []) [], [],
_prop("v", g, g.vertex_index))
for k, v in g.properties.items(): for k, v in g.properties.items():
self.properties[k] = self.own_property(v) self.properties[k] = self.own_property(v)
......
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