Commit 96b9c5e7 authored by Tiago Peixoto's avatar Tiago Peixoto

Add centrality module

This adds the centrality module, which supports betweenness, eigentrust,
pagerank and absolute trust.
parent d0a73fff
......@@ -293,6 +293,7 @@ src/graph/Makefile
src/graph/correlations/Makefile
src/graph/generation/Makefile
src/graph/stats/Makefile
src/graph/centrality/Makefile
src/graph/clustering/Makefile
src/graph/community/Makefile
src/graph/util/Makefile
......
## Process this file with automake to produce Makefile.in
SUBDIRS = generation correlations stats clustering community util misc
SUBDIRS = generation stats clustering community util misc centrality correlations
AM_CPPFLAGS =\
-I$(srcdir)/.. \
......
## Process this file with automake to produce Makefile.in
AM_CPPFLAGS = $(MOD_CPPFLAGS)
AM_CFLAGS=$(AM_CXXFLAGS)
libgraph_tool_centralitydir = $(MOD_DIR)/centrality
libgraph_tool_centrality_LTLIBRARIES = libgraph_tool_centrality.la
libgraph_tool_centrality_la_includedir = $(MOD_DIR)/include
libgraph_tool_centrality_la_LIBADD = $(MOD_LIBADD)
libgraph_tool_centrality_la_LDFLAGS = $(MOD_LDFLAGS)
libgraph_tool_centrality_la_SOURCES = \
graph_betweenness.cc \
graph_pagerank.cc \
graph_eigentrust.cc \
graph_absolute_trust.cc \
graph_centrality_bind.cc
libgraph_tool_centrality_la_include_HEADERS =
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007 Tiago de Paula Peixoto <tiago@forked.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph_filtering.hh"
#include <boost/python.hpp>
#include <boost/lambda/bind.hpp>
#include "graph.hh"
#include "graph_selectors.hh"
#include <boost/random.hpp>
typedef boost::mt19937 rng_t;
#include "graph_absolute_trust.hh"
using namespace std;
using namespace boost;
using namespace graph_tool;
void absolute_trust(GraphInterface& g, boost::any c, boost::any t,
double epslon, size_t max_iter, size_t seed)
{
rng_t rng(static_cast<rng_t::result_type>(seed));
if (!belongs<edge_floating_properties>()(c))
throw GraphException("edge property must be of floating point value type");
if (!belongs<vertex_floating_vector_properties>()(t))
throw GraphException("vertex property must be of floating point vector value type");
run_action<>()
(g, bind<void>
(get_eigentrust(),
_1, g.GetVertexIndex(), g.GetEdgeIndex(), _2,
_3, epslon, max_iter, ref(rng)),
edge_floating_properties(),
vertex_floating_vector_properties())(c,t);
}
void export_absolute_trust()
{
using namespace boost::python;
def("get_absolute_trust", &absolute_trust);
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007 Tiago de Paula Peixoto <tiago@forked.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef GRAPH_ABSOLUTE_TRUST_HH
#define GRAPH_ABSOLUTE_TRUST_HH
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_util.hh"
#include <boost/random/uniform_int.hpp>
namespace graph_tool
{
using namespace std;
using namespace boost;
struct get_eigentrust
{
template <class Graph, class VertexIndex, class EdgeIndex, class TrustMap,
class InferredTrustMap>
void operator()(Graph* gp, VertexIndex vertex_index, EdgeIndex edge_index,
TrustMap c, InferredTrustMap t, double epslon,
size_t max_iter, rng_t& rng)
const
{
Graph& g = *gp;
typedef typename property_traits<TrustMap>::value_type c_type;
typedef typename property_traits<InferredTrustMap>::value_type
::value_type t_type;
unchecked_vector_property_map<vector<size_t>, VertexIndex>
t_count(vertex_index, num_vertices(g));
unchecked_vector_property_map<vector<size_t>, VertexIndex>
v_mark(vertex_index, num_vertices(g));
// init inferred trust t
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(dynamic)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
t[v].resize(N);
t_count[v].resize(N,0);
v_mark[v].resize(N,0);
}
t_type delta = 2*epslon;
size_t iter = 0;
while (delta >= epslon)
{
delta = 0;
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(dynamic) reduction(+:delta)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v =
vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
typename graph_traits<Graph>::vertex_descriptor pos = v;
t_type pos_t = 1.0;
v_mark[v][vertex_index[v]] = iter+1;
// start a self-avoiding walk from vertex v
vector<typename graph_traits<Graph>::edge_descriptor> out_es;
vector<t_type> out_prob;
do
{
out_es.clear();
out_prob.clear();
// obtain list of candidate edges to follow
typename graph_traits<Graph>::out_edge_iterator e, e_end;
for (tie(e, e_end) = out_edges(pos, g); e != e_end; ++e)
{
typename graph_traits<Graph>::vertex_descriptor t =
target(*e,g);
if (v_mark[v][vertex_index[t]] <= iter)
{
out_es.push_back(*e);
if (out_prob.empty())
out_prob.push_back(c[*e]);
else
out_prob.push_back(out_prob.back()+c[*e]);
}
}
if (!out_es.empty())
{
// select edge according to its probability
typename graph_traits<Graph>::edge_descriptor e;
uniform_real<t_type> random(0,out_prob.back());
t_type u;
{
#pragma omp critical
u = random(rng);
}
e = out_es[lower_bound(out_prob.begin(),
out_prob.end(), u) -
out_prob.begin()];
pos = target(e,g);
size_t posi = vertex_index[pos];
//update current path trust, and update new vertex
pos_t *= c[e];
t_type old = 0;
if (t_count[v][posi] > 0)
old = t[v][posi]/t_count[v][posi];
t[v][posi] += pos_t;
t_count[v][posi]++;
delta += abs(old - t[v][posi]/t_count[v][posi]);
v_mark[v][posi] = iter+1; // mark vertex
}
}
while (!out_es.empty());
}
++iter;
if (max_iter > 0 && iter == max_iter)
break;
}
#pragma omp parallel for default(shared) private(i) \
schedule(dynamic)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
for (size_t j = 0; j < N; ++j)
if (t_count[v][j] > 0)
t[v][j] /= t_count[v][j];
}
}
};
}
#endif
......@@ -17,11 +17,13 @@
#include "graph_filtering.hh"
#include <boost/python.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/graph/betweenness_centrality.hpp>
#include "graph.hh"
#include "graph_selectors.hh"
#include "graph_util.hh"
using namespace std;
using namespace boost;
......@@ -31,9 +33,9 @@ using namespace graph_tool;
template <class Graph, class EdgeBetweenness, class VertexBetweenness>
void normalize_betweenness(const Graph& g,
EdgeBetweenness edge_betweenness,
VertexBetweenness vertex_betweenness)
VertexBetweenness vertex_betweenness,
size_t n)
{
size_t n = HardNumVertices()(g);
double vfactor = (n > 2) ? 1.0/((n-1)*(n-2)) : 1.0;
double efactor = (n > 1) ? 1.0/(n*(n-1)) : 1.0;
if (is_convertible<typename graph_traits<Graph>::directed_category,
......@@ -43,10 +45,15 @@ void normalize_betweenness(const Graph& g,
efactor *= 2;
}
typename graph_traits<Graph>::vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(g); v != v_end; ++v)
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(dynamic)
for (i = 0; i < N; ++i)
{
put(vertex_betweenness, *v, vfactor * get(vertex_betweenness, *v));
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
put(vertex_betweenness, v, vfactor * get(vertex_betweenness, v));
}
typename graph_traits<Graph>::edge_iterator e, e_end;
......@@ -58,11 +65,12 @@ void normalize_betweenness(const Graph& g,
struct get_betweenness
{
template <class Graph, class VertexIndexMap, class EdgeBetweenness,
class VertexBetweenness>
void operator()(const Graph* gp, VertexIndexMap index_map,
template <class Graph, class EdgeBetweenness, class VertexBetweenness>
void operator()(Graph* gp,
GraphInterface::vertex_index_map_t index_map,
EdgeBetweenness edge_betweenness,
VertexBetweenness vertex_betweenness) const
VertexBetweenness vertex_betweenness,
bool normalize, size_t n) const
{
vector<vector<typename graph_traits<Graph>::edge_descriptor> >
incoming_map(num_vertices(*gp));
......@@ -72,108 +80,78 @@ struct get_betweenness
vector<size_t> path_count_map(num_vertices(*gp));
brandes_betweenness_centrality
(*gp, vertex_betweenness,edge_betweenness,
(*gp, vertex_betweenness, edge_betweenness,
make_iterator_property_map(incoming_map.begin(), index_map),
make_iterator_property_map(distance_map.begin(), index_map),
make_iterator_property_map(dependency_map.begin(), index_map),
make_iterator_property_map(path_count_map.begin(), index_map),
index_map);
normalize_betweenness(*gp, edge_betweenness, vertex_betweenness);
if (normalize)
normalize_betweenness(*gp, edge_betweenness, vertex_betweenness, n);
}
};
template <class VertexIndexMap>
struct get_weighted_betweenness
{
get_weighted_betweenness(VertexIndexMap index): _vertex_index(index) {}
template <class Graph, class EdgeBetweenness, class VertexBetweenness,
class WeightMap>
void operator()(const Graph* gp, EdgeBetweenness edge_betweenness,
VertexBetweenness vertex_betweenness,
WeightMap weight_map) const
class VertexIndexMap>
void operator()(Graph* gp, VertexIndexMap vertex_index,
EdgeBetweenness edge_betweenness,
VertexBetweenness vertex_betweenness,
boost::any weight_map, bool normalize,
size_t n) const
{
vector<vector<typename graph_traits<Graph>::edge_descriptor> >
incoming_map(num_vertices(*gp));
vector<typename property_traits<WeightMap>::value_type>
vector<typename property_traits<EdgeBetweenness>::value_type>
distance_map(num_vertices(*gp));
vector<typename property_traits<VertexBetweenness>::value_type>
dependency_map(num_vertices(*gp));
vector<size_t> path_count_map(num_vertices(*gp));
brandes_betweenness_centrality
(*gp, vertex_betweenness,edge_betweenness,
make_iterator_property_map(incoming_map.begin(), _vertex_index),
make_iterator_property_map(distance_map.begin(), _vertex_index),
make_iterator_property_map(dependency_map.begin(), _vertex_index),
make_iterator_property_map(path_count_map.begin(), _vertex_index),
_vertex_index, weight_map);
normalize_betweenness(*gp, edge_betweenness, vertex_betweenness);
(*gp, vertex_betweenness, edge_betweenness,
make_iterator_property_map(incoming_map.begin(), vertex_index),
make_iterator_property_map(distance_map.begin(), vertex_index),
make_iterator_property_map(dependency_map.begin(), vertex_index),
make_iterator_property_map(path_count_map.begin(), vertex_index),
vertex_index, any_cast<EdgeBetweenness>(weight_map));
if (normalize)
normalize_betweenness(*gp, edge_betweenness, vertex_betweenness, n);
}
VertexIndexMap _vertex_index;
};
void GraphInterface::GetBetweenness(string weight, string edge_betweenness,
string vertex_betweenness)
void betweenness(GraphInterface& g, boost::any weight,
boost::any edge_betweenness,
boost::any vertex_betweenness,
bool normalize)
{
boost::any edge_prop, vertex_prop;
try
{
find_property_map(_properties, edge_betweenness, typeid(edge_t));
edge_prop = prop(edge_betweenness, _edge_index, _properties);
if (!belongs<edge_floating_properties>()(edge_prop))
throw GraphException("edge property " + edge_betweenness +
" is not of floating type");
}
catch (property_not_found)
{
typedef vector_property_map<double, edge_index_map_t>
edge_betweenness_map_t;
edge_betweenness_map_t edge_betweenness_map(_edge_index);
edge_prop = edge_betweenness_map;
}
if (!belongs<edge_floating_properties>()(edge_betweenness))
throw GraphException("edge property must be of floating point value type");
try
{
find_property_map(_properties, vertex_betweenness, typeid(vertex_t));
vertex_prop = prop(vertex_betweenness, _vertex_index, _properties);
if (!belongs<vertex_floating_properties>()(vertex_prop))
throw GraphException("vertex property " + vertex_betweenness +
" is not of floating type");
}
catch (property_not_found)
{
typedef vector_property_map<double, vertex_index_map_t>
vertex_betweenness_map_t;
vertex_betweenness_map_t vertex_betweenness_map(_vertex_index);
vertex_prop = vertex_betweenness_map;
}
if (!belongs<vertex_floating_properties>()(vertex_betweenness))
throw GraphException("vertex property must be of floating point value type");
if (weight != "")
if (!weight.empty())
{
try
{
run_action<>()
(*this,
get_weighted_betweenness<vertex_index_map_t>(_vertex_index),
edge_floating_properties(), vertex_floating_properties(),
edge_scalar_properties())(edge_prop, vertex_prop,
prop(weight, _edge_index,
_properties));
}
catch (property_not_found& e)
{
throw GraphException("edge property " + weight + " not found");
}
run_action<>()
(g, lambda::bind<void>
(get_weighted_betweenness(), lambda::_1, g.GetVertexIndex(),
lambda::_2, lambda::_3, weight, normalize,
g.GetNumberOfVertices()),
edge_floating_properties(),
vertex_floating_properties())
(edge_betweenness, vertex_betweenness);
}
else
{
run_action<>()(*this, bind<void>(get_betweenness(), _1,
_vertex_index, _2, _3),
edge_floating_properties(), vertex_floating_properties())
(edge_prop, vertex_prop);
run_action<>()
(g, lambda::bind<void>
(get_betweenness(), lambda::_1, g.GetVertexIndex(), lambda::_2,
lambda::_3, normalize, g.GetNumberOfVertices()),
edge_floating_properties(),
vertex_floating_properties())
(edge_betweenness, vertex_betweenness);
}
}
......@@ -187,27 +165,20 @@ struct get_central_point_dominance
}
};
double GraphInterface::GetCentralPointDominance(string vertex_betweenness)
double central_point(GraphInterface& g,
boost::any vertex_betweenness)
{
try
{
double c = 0.0;
bool directed = this->GetDirected();
bool reversed = this->GetReversed();
this->SetReversed(false);
this->SetDirected(true);
run_action<detail::never_reversed>()
(*this, bind<void>(get_central_point_dominance(), _1, _2,
var(c)), vertex_scalar_properties())
(prop(vertex_betweenness, _vertex_index, _properties));
this->SetReversed(reversed);
this->SetDirected(directed);
return c;
}
catch (property_not_found)
{
throw GraphException("vertex property " + vertex_betweenness
+ " not found");
}
double c = 0.0;
run_action<graph_tool::detail::never_reversed>()
(g, lambda::bind<void>(get_central_point_dominance(), lambda::_1,
lambda::_2, var(c)),
vertex_scalar_properties()) (vertex_betweenness);
return c;
}
void export_betweenness()
{
using namespace boost::python;
def("get_betweenness", &betweenness);
def("get_central_point_dominance", &central_point);
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007 Tiago de Paula Peixoto <tiago@forked.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <boost/python.hpp>
using namespace boost;
void export_betweenness();
void export_eigentrust();
void export_absolute_trust();
void export_pagerank();
BOOST_PYTHON_MODULE(libgraph_tool_centrality)
{
export_betweenness();
export_eigentrust();
export_absolute_trust();
export_pagerank();
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007 Tiago de Paula Peixoto <tiago@forked.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph_filtering.hh"
#include <boost/python.hpp>
#include <boost/lambda/bind.hpp>
#include "graph.hh"
#include "graph_selectors.hh"
#include "graph_eigentrust.hh"
using namespace std;
using namespace boost;
using namespace graph_tool;
void eigentrust(GraphInterface& g, boost::any c, boost::any t,
double epslon, size_t max_iter)
{
if (!belongs<writable_edge_scalar_properties>()(c))
throw GraphException("edge property must be writable");
if (!belongs<vertex_floating_vector_properties>()(t))
throw GraphException("vertex property must be of floating point value type");
run_action<>()
(g, bind<void>
(get_eigentrust(),
_1, g.GetVertexIndex(), g.GetEdgeIndex(), _2,
_3, epslon, max_iter),
writable_edge_scalar_properties(),
vertex_floating_properties())(c,t);
}
void export_eigentrust()
{
using namespace boost::python;
def("get_eigentrust", &eigentrust);
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007 Tiago de Paula Peixoto <tiago@forked.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef GRAPH_TRUST_HH
#define GRAPH_TRUST_HH
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_util.hh"