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

Implement weighted degree property maps and weighted degree selectors

parent 0c4b511c
......@@ -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(); }
......
......@@ -366,7 +366,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
mpl::for_each<mpl::push_back<scalar_types,string>::type>(export_vector_types());
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("GetNumberOfEdges", &GraphInterface::GetNumberOfEdges)
.def("SetDirected", &GraphInterface::SetDirected)
......@@ -445,4 +445,3 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
def("get_graph_type", &get_graph_type);
}
......@@ -158,6 +158,7 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
ref(python::extract<boost::any&>(oeprops[i][1])())));
}
boost::any avorder = python::extract<boost::any>(vorder);
run_action<>()
(const_cast<GraphInterface&>(gi),
bind<void>(do_graph_copy(), _1, ref(*_mg),
......
......@@ -230,9 +230,19 @@ void remove_edge(GraphInterface& gi, const python::object& e)
struct get_degree_map
{
template <class Graph, class DegreeMap, class DegS>
void operator()(const Graph& g, DegreeMap deg_map, DegS deg) const
template <class Graph, class DegS, class Weight>
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);
#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<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
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);
deg_map.reserve(num_vertices(*_mg));
python::object deg_map;
typedef typename mpl::push_back<edge_scalar_properties,
detail::no_weightS>::type weight_t;
if (weight.empty())
weight = detail::no_weightS();
if (deg == "in")
run_action<>()(const_cast<GraphInterface&>(*this),
bind<void>(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<GraphInterface&>(*this),
bind<void>(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<GraphInterface&>(*this),
bind<void>(get_degree_map(), _1,
deg_map, total_degreeS()))();
return python::object(PythonPropertyMap<map_t>(deg_map));
ref(deg_map), total_degreeS(), _2), weight_t())
(weight);
return deg_map;
}
//
......
......@@ -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 <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;
total_degreeS() {}
in_degreeS() {}
template <class Graph, class Vertex>
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;
typedef typename is_convertible
<typename graph_traits<Graph>::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 <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
{
return in_degree(v,g)+out_degree(v,g);
return in_degree(v, g);
}
template <class Graph, class Vertex>
size_t get_total_degree(const Vertex& v, const Graph &g, boost::false_type)
template <class Graph, class Vertex, class Weight>
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
{
return out_degree(v,g);
return 0;
}
};
struct in_degreeS
struct out_degreeS
{
typedef size_t value_type;
in_degreeS() {}
out_degreeS() {}
template <class Graph, class Vertex>
size_t operator()(const Vertex& v, const Graph &g) const
{
using namespace boost;
typedef typename is_convertible
<typename graph_traits<Graph>::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 <class Graph, class Vertex>
size_t get_in_degree(const Vertex& v, const Graph &g, boost::true_type)
template <class Graph, class Vertex, class Weight>
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
{
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>
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 <class Graph, class Vertex>
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>
struct scalarS
{
......
......@@ -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)
......
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