Commit d7876c80 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Implement blockmodel inference in community module

parent f4234551
.. automodule:: graph_tool.community
:members:
:undoc-members:
:member-order: "bysource"
\ No newline at end of file
......@@ -15,9 +15,13 @@ libgraph_tool_community_la_LIBADD = $(MOD_LIBADD)
libgraph_tool_community_la_LDFLAGS = $(MOD_LDFLAGS)
libgraph_tool_community_la_SOURCES = \
graph_blockmodel.cc \
graph_community.cc \
graph_community_network.cc
graph_community_network.cc \
graph_community_network_vavg.cc \
graph_community_network_eavg.cc
libgraph_tool_community_la_include_HEADERS = \
graph_blockmodel.hh \
graph_community.hh \
graph_community_network.hh
This diff is collapsed.
This diff is collapsed.
......@@ -34,7 +34,7 @@ using namespace graph_tool;
void community_structure(GraphInterface& g, double gamma, string corr_name,
size_t n_iter, double Tmin, double Tmax, size_t Nspins,
size_t seed, bool verbose, string history_file,
rng_t& rng, bool verbose, string history_file,
boost::any weight, boost::any property)
{
typedef property_map_types::apply<mpl::vector<int32_t,int64_t>,
......@@ -69,7 +69,7 @@ void community_structure(GraphInterface& g, double gamma, string corr_name,
(g, bind<void>(get_communities_selector(corr, g.GetVertexIndex()),
_1, _2, _3, gamma, n_iter,
make_pair(Tmin, Tmax), Nspins,
seed, make_pair(verbose,history_file)),
ref(rng), make_pair(verbose,history_file)),
weight_properties(), allowed_spin_properties())
(weight, property);
}
......@@ -103,9 +103,31 @@ extern void community_network(GraphInterface& gi, GraphInterface& cgi,
boost::any edge_count, boost::any vweight,
boost::any eweight, bool self_loops);
void community_network_vavg(GraphInterface& gi, GraphInterface& cgi,
boost::any community_property,
boost::any condensed_community_property,
boost::any vertex_count,
boost::any vweight,
python::list avprops);
void community_network_eavg(GraphInterface& gi, GraphInterface& cgi,
boost::any community_property,
boost::any condensed_community_property,
boost::any edge_count,
boost::any eweight,
python::list aeprops,
bool self_loops);
extern void export_blockmodel();
BOOST_PYTHON_MODULE(libgraph_tool_community)
{
def("community_structure", &community_structure);
def("modularity", &modularity);
def("community_network", &community_network);
def("community_network_vavg", &community_network_vavg);
def("community_network_eavg", &community_network_eavg);
export_blockmodel();
}
......@@ -20,11 +20,9 @@
#if (GCC_VERSION >= 40400)
# include <tr1/unordered_set>
# include <tr1/random>
# include <tr1/tuple>
#else
# include <boost/tr1/unordered_set.hpp>
# include <boost/tr1/random.hpp>
# include <boost/tr1/tuple.hpp>
#endif
#include <iostream>
......@@ -36,6 +34,7 @@
#include "graph_util.hh"
#include "graph_properties.hh"
#include "random.hh"
namespace graph_tool
{
......@@ -46,8 +45,6 @@ using namespace boost;
using std::tr1::unordered_map;
using std::tr1::unordered_set;
typedef tr1::mt19937 rng_t;
// computes the community structure through a spin glass system with
// simulated annealing
......@@ -58,15 +55,13 @@ struct get_communities
class CommunityMap>
void operator()(const Graph& g, VertexIndex vertex_index, WeightMap weights,
CommunityMap s, double gamma, size_t n_iter,
pair<double, double> Tinterval, size_t n_spins, size_t seed,
pair<double, double> Tinterval, size_t n_spins, rng_t& rng,
pair<bool, string> verbose) const
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename property_traits<WeightMap>::key_type weight_key_t;
rng_t rng(static_cast<rng_t::result_type>(seed));
tr1::variate_generator<rng_t&, tr1::uniform_real<> >
random(rng, tr1::uniform_real<>());
......@@ -472,23 +467,23 @@ struct get_communities_selector
template <class Graph, class WeightMap, class CommunityMap>
void operator()(const Graph& g, WeightMap weights, CommunityMap s,
double gamma, size_t n_iter, pair<double, double> Tinterval,
size_t Nspins, size_t seed, pair<bool, string> verbose)
size_t Nspins, rng_t& rng, pair<bool, string> verbose)
const
{
switch (_corr)
{
case ERDOS_REYNI:
get_communities<NNKSErdosReyni>()(g, _index, weights, s, gamma,
n_iter, Tinterval, Nspins, seed,
n_iter, Tinterval, Nspins, rng,
verbose);
break;
case UNCORRELATED:
get_communities<NNKSUncorr>()(g, _index, weights, s, gamma, n_iter,
Tinterval, Nspins, seed, verbose);
Tinterval, Nspins, rng, verbose);
break;
case CORRELATED:
get_communities<NNKSCorr>()(g, _index, weights, s, gamma, n_iter,
Tinterval, Nspins, seed, verbose);
Tinterval, Nspins, rng, verbose);
break;
}
}
......
......@@ -35,71 +35,49 @@ using namespace graph_tool;
typedef ConstantPropertyMap<int32_t,GraphInterface::edge_t> no_eweight_map_t;
typedef ConstantPropertyMap<int32_t,GraphInterface::vertex_t> no_vweight_map_t;
typedef DynamicPropertyMapWrap<int32_t,GraphInterface::vertex_t> viweight_map_t;
typedef DynamicPropertyMapWrap<double,GraphInterface::vertex_t> vweight_map_t;
typedef DynamicPropertyMapWrap<int32_t,GraphInterface::edge_t> eiweight_map_t;
typedef DynamicPropertyMapWrap<double,GraphInterface::edge_t> eweight_map_t;
typedef DynamicPropertyMapWrap<python::object,GraphInterface::vertex_t> voweight_map_t;
typedef DynamicPropertyMapWrap<python::object,GraphInterface::edge_t> eoweight_map_t;
struct get_community_network_dispatch
{
get_community_network_dispatch(bool self_loops): _self_loops(self_loops) {}
bool _self_loops;
typedef property_map_type::apply<int32_t,GraphInterface::edge_index_map_t>::type::unchecked_t ecount_map_t;
typedef property_map_type::apply<int32_t,GraphInterface::vertex_index_map_t>::type::unchecked_t vcount_map_t;
struct get_community_network_vertices_dispatch
{
template <class Graph, class CommunityGraph, class CommunityMap,
class VertexWeightMap, class EdgeWeightMap, class EdgeIndex,
class VertexIndex>
class VertexWeightMap>
void operator()(const Graph& g, CommunityGraph& cg,
VertexIndex, EdgeIndex cedge_index,
CommunityMap s_map, boost::any acs_map,
VertexWeightMap vweight, EdgeWeightMap eweight,
pair<boost::any,boost::any> count) const
VertexWeightMap vweight, boost::any vcount) const
{
typedef typename get_prop_type<CommunityMap, VertexIndex>::type
comm_t;
comm_t cs_map = boost::any_cast<comm_t>(acs_map);
typename CommunityMap::checked_t cs_map = boost::any_cast<typename CommunityMap::checked_t>(acs_map);
typedef typename mpl::if_<is_same<no_vweight_map_t, VertexWeightMap>,
viweight_map_t, VertexWeightMap>::type vweight_t;
typedef typename mpl::if_<is_same<no_eweight_map_t, EdgeWeightMap>,
eiweight_map_t, EdgeWeightMap>::type eweight_t;
vcount_map_t, VertexWeightMap>::type vweight_t;
typename vweight_t::checked_t vertex_count = boost::any_cast<typename vweight_t::checked_t>(vcount);
vweight_t vertex_count = boost::any_cast<vweight_t>(count.first);
eweight_t edge_count = boost::any_cast<eweight_t>(count.second);
get_community_network()(g, cg, cedge_index, s_map,
cs_map, vweight, eweight, vertex_count,
edge_count, _self_loops);
get_community_network_vertices()(g, cg, s_map, cs_map, vweight, vertex_count);
}
struct get_checked_t
{
template <class PropertyMap>
struct apply
{
typedef typename PropertyMap::checked_t type;
};
};
struct get_identity
{
template <class PropertyMap>
struct apply
{
typedef PropertyMap type;
};
};
template <class PropertyMap, class IndexMap>
struct get_prop_type
};
struct get_community_network_edges_dispatch
{
get_community_network_edges_dispatch(bool self_loops): _self_loops(self_loops) {}
bool _self_loops;
template <class Graph, class CommunityGraph, class CommunityMap,
class EdgeWeightMap, class EdgeIndex>
void operator()(const Graph& g, CommunityGraph& cg, EdgeIndex cedge_index,
CommunityMap s_map, boost::any acs_map,
EdgeWeightMap eweight, boost::any ecount) const
{
typedef typename mpl::if_<typename is_same<PropertyMap, IndexMap>::type,
get_identity,
get_checked_t>::type extract;
typedef typename extract::template apply<PropertyMap>::type type;
};
typename CommunityMap::checked_t cs_map = boost::any_cast<typename CommunityMap::checked_t>(acs_map);
typedef typename mpl::if_<is_same<no_eweight_map_t, EdgeWeightMap>,
ecount_map_t, EdgeWeightMap>::type eweight_t;
typename eweight_t::checked_t edge_count = boost::any_cast<typename eweight_t::checked_t>(ecount);
get_community_network_edges()(g, cg, cedge_index, s_map,
cs_map, eweight, edge_count,
_self_loops);
}
};
......@@ -108,58 +86,52 @@ void community_network(GraphInterface& gi, GraphInterface& cgi,
boost::any condensed_community_property,
boost::any vertex_count,
boost::any edge_count, boost::any vweight,
boost::any eweight, bool self_loops)
boost::any eweight,
bool self_loops)
{
typedef mpl::vector<vweight_map_t, voweight_map_t, no_vweight_map_t>::type
typedef mpl::push_back<writable_vertex_scalar_properties, no_vweight_map_t>::type
vweight_properties;
typedef mpl::vector<eweight_map_t, eoweight_map_t, no_eweight_map_t>::type
typedef mpl::push_back<writable_edge_scalar_properties, no_eweight_map_t>::type
eweight_properties;
if (eweight.empty())
{
eweight = no_eweight_map_t(1);
edge_count = eiweight_map_t(edge_count, edge_scalar_properties());
}
else
{
try
{
eweight = eweight_map_t(eweight, edge_scalar_properties());
edge_count = eweight_map_t(edge_count, edge_scalar_properties());
}
catch (...)
{
eweight = eoweight_map_t(eweight, edge_properties());
edge_count = eoweight_map_t(edge_count, edge_properties());
}
}
if (vweight.empty())
{
vweight = no_vweight_map_t(1);
vertex_count = viweight_map_t(vertex_count, vertex_scalar_properties());
}
else
{
try
{
vweight = vweight_map_t(vweight, vertex_scalar_properties());
vertex_count = vweight_map_t(vertex_count, vertex_scalar_properties());
}
catch (...)
{
vweight = voweight_map_t(vweight, vertex_properties());
vertex_count = voweight_map_t(vertex_count, vertex_properties());
}
}
run_action<>()(gi, bind<void>(get_community_network_dispatch(self_loops),
_1, ref(cgi.GetGraph()), cgi.GetVertexIndex(),
cgi.GetEdgeIndex(), _2,
condensed_community_property,
_3, _4, make_pair(vertex_count, edge_count)),
vertex_scalar_properties(), vweight_properties(),
eweight_properties())
(community_property, vweight, eweight);
cgi.ReIndexEdges();
typedef mpl::insert_range<writable_vertex_scalar_properties,
mpl::end<writable_vertex_scalar_properties>::type,
vertex_scalar_vector_properties>::type vprops_temp;
typedef mpl::push_back<vprops_temp,
property_map_type::apply<python::object,
GraphInterface::vertex_index_map_t>::type>::type
vprops_t;
typedef mpl::insert_range<writable_edge_scalar_properties,
mpl::end<writable_edge_scalar_properties>::type,
edge_scalar_vector_properties>::type eprops_temp;
typedef mpl::push_back<eprops_temp,
property_map_type::apply<python::object,
GraphInterface::edge_index_map_t>::type>::type
eprops_t;
run_action<>()
(gi, bind<void>(get_community_network_vertices_dispatch(),
_1, ref(cgi.GetGraph()),
_2, condensed_community_property,
_3, vertex_count),
writable_vertex_properties(), vweight_properties())
(community_property, vweight);
run_action<>()
(gi, bind<void>(get_community_network_edges_dispatch(self_loops),
_1, ref(cgi.GetGraph()), cgi.GetEdgeIndex(),
_2, condensed_community_property,
_3, edge_count),
writable_vertex_properties(), eweight_properties())
(community_property, eweight);
cgi.ReIndexEdges();
}
......@@ -34,16 +34,14 @@ using namespace boost;
// retrieves the network of communities given a community structure
struct get_community_network
struct get_community_network_vertices
{
template <class Graph, class CommunityGraph, class CommunityMap,
class CCommunityMap, class VertexWeightMap, class EdgeWeightMap,
class EdgeIndex, class VertexProperty, class EdgeProperty>
void operator()(const Graph& g, CommunityGraph& cg, EdgeIndex cedge_index,
CommunityMap s_map, CCommunityMap cs_map,
VertexWeightMap vweight, EdgeWeightMap eweight,
VertexProperty vertex_count, EdgeProperty edge_count,
bool self_loops) const
class CCommunityMap, class VertexWeightMap,
class VertexProperty>
void operator()(const Graph& g, CommunityGraph& cg, CommunityMap s_map,
CCommunityMap cs_map, VertexWeightMap vweight,
VertexProperty vertex_count) const
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
......@@ -56,30 +54,72 @@ struct get_community_network
typedef typename boost::property_traits<VertexProperty>::value_type
vprop_type;
tr1::unordered_map<s_type, pair<vector<vertex_t>, vprop_type>, hash<s_type> >
comms;
// create vertices
tr1::unordered_map<s_type, vertex_t, hash<s_type> > comms;
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
{
pair<vector<vertex_t>, vprop_type>& m = comms[get(s_map, *vi)];
m.first.push_back(*vi);
m.second += get(vweight, *vi);
}
// create vertices
tr1::unordered_map<s_type, cvertex_t, hash<s_type> >
comm_vertices;
for (typeof(comms.begin()) iter = comms.begin(); iter != comms.end();
++iter)
{
cvertex_t v = add_vertex(cg);
put(vertex_count, v, iter->second.second);
comm_vertices[iter->first] = v;
put_dispatch(cs_map, v, iter->first,
typename boost::is_convertible
<typename property_traits<CommunityMap>::category,
s_type s = get(s_map, *vi);
typeof(comms.begin()) iter = comms.find(s);
cvertex_t v;
if (iter == comms.end())
{
comms[s] = v = add_vertex(cg);
put_dispatch(cs_map, v, s,
typename boost::is_convertible
<typename property_traits<CommunityMap>::category,
writable_property_map_tag>::type());
}
else
{
v = iter->second;
}
put(vertex_count, v, get(vertex_count, v) + get(vweight, *vi));
}
}
template <class PropertyMap>
void put_dispatch(PropertyMap cs_map,
const typename property_traits<PropertyMap>::key_type& v,
const typename property_traits<PropertyMap>::value_type& val,
mpl::true_ /*is_writable*/) const
{
put(cs_map, v, val);
}
template <class PropertyMap>
void put_dispatch(PropertyMap,
const typename property_traits<PropertyMap>::key_type&,
const typename property_traits<PropertyMap>::value_type&,
mpl::false_ /*is_writable*/) const
{
}
};
struct get_community_network_edges
{
template <class Graph, class CommunityGraph, class CommunityMap,
class CCommunityMap, class EdgeWeightMap,
class EdgeIndex, class EdgeProperty>
void operator()(const Graph& g, CommunityGraph& cg, EdgeIndex cedge_index,
CommunityMap s_map, CCommunityMap cs_map,
EdgeWeightMap eweight, EdgeProperty edge_count,
bool self_loops) const
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename graph_traits<CommunityGraph>::vertex_descriptor
cvertex_t;
typedef typename graph_traits<CommunityGraph>::edge_descriptor
cedge_t;
typedef typename boost::property_traits<CommunityMap>::value_type
s_type;
tr1::unordered_map<s_type, vertex_t, hash<s_type> > comms;
typename graph_traits<CommunityGraph>::vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(cg); v != v_end; ++v)
comms[cs_map[*v]] = *v;
// create edges
tr1::unordered_map<pair<size_t, size_t>,
......@@ -88,8 +128,8 @@ struct get_community_network
typename graph_traits<Graph>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(g); e != e_end; ++e)
{
cvertex_t cs = comm_vertices[get(s_map, source(*e, g))];
cvertex_t ct = comm_vertices[get(s_map, target(*e, g))];
cvertex_t cs = comms[get(s_map, source(*e, g))];
cvertex_t ct = comms[get(s_map, target(*e, g))];
if (ct == cs && !self_loops)
continue;
cedge_t ce;
......@@ -107,26 +147,180 @@ struct get_community_network
put(edge_count, ce, get(edge_count, ce) + get(eweight, *e));
}
}
};
template <class PropertyMap>
void put_dispatch(PropertyMap cs_map,
const typename property_traits<PropertyMap>::key_type& v,
const typename property_traits<PropertyMap>::value_type& val,
mpl::true_ /*is_writable*/) const
template <class T1, class T2>
inline vector<T1> operator*(const vector<T1>& v, const T2& c)
{
vector<T1> r(v);
for (size_t i = 0; i < r.size(); ++i)
r[i] = v[i] * c;
return r;
}
template <class T1, class T2>
inline void operator/=(vector<T1>& v, const T2& c)
{
for (size_t i = 0; i < v.size(); ++i)
v[i] /= c;
}
template <class T1, class T2>
inline vector<T1> operator*(const vector<T1>& v1, const vector<T2>& v2)
{
vector<T1> r(max(v1.size(), v2.size()));
for (size_t i = 0; i < min(v1.size(), v2.size()); ++i)
r[i] = v1[i] * v2[i];
return r;
}
template <class T1, class T2>
inline void operator/=(vector<T1>& v1, const vector<T2>& v2)
{
v1.resize(max(v1.size(), v2.size()));
for (size_t i = 0; i < v2.size(); ++i)
v1[i] /= v2[i];
return v1;
}
template <class T1, class T2>
inline void operator+=(vector<T1>& v1, const vector<T2>& v2)
{
v1.resize(max(v1.size(), v2.size()));
for (size_t i = 0; i < v2.size(); ++i)
v1[i] += v2[i];
}
// retrieves the average property of a community structure
struct get_weighted_vertex_property
{
template <class Graph, class VertexWeightMap, class Vprop>
void operator()(const Graph& g, VertexWeightMap vweight, Vprop vprop,
Vprop temp) const
{
put(cs_map, v, val);
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
temp[*vi] = vprop[*vi] * get(vweight, *vi);
}
};
template <class PropertyMap>
void put_dispatch(PropertyMap,
const typename property_traits<PropertyMap>::key_type&,
const typename property_traits<PropertyMap>::value_type&,
mpl::false_ /*is_writable*/) const
struct get_vertex_community_property_sum
{
template <class Graph, class CommunityGraph, class CommunityMap,
class CCommunityMap, class Vprop>
void operator()(const Graph& g, CommunityGraph& cg, CommunityMap s_map,
CCommunityMap cs_map, Vprop vprop, Vprop cvprop) const
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename graph_traits<CommunityGraph>::vertex_descriptor
cvertex_t;
typedef typename boost::property_traits<CommunityMap>::value_type
s_type;
tr1::unordered_map<s_type, vertex_t, hash<s_type> > comms;
typename graph_traits<CommunityGraph>::vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(cg); v != v_end; ++v)
comms[cs_map[*v]] = *v;
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
{
s_type s = get(s_map, *vi);
cvprop[comms[s]] += vprop[*vi];
}
}
};
struct get_vertex_community_property_norm
{
template <class CommunityGraph, class VertexCountMap, class Vprop>
void operator()(const CommunityGraph& cg, VertexCountMap vertex_count,
Vprop cvprop) const
{
typename graph_traits<CommunityGraph>::vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(cg); v != v_end; ++v)