Commit 95470ff4 authored by Tiago Peixoto's avatar Tiago Peixoto

Implement eigenvector centrality

parent ef9ad955
......@@ -16,13 +16,15 @@ libgraph_tool_centrality_la_LDFLAGS = $(MOD_LDFLAGS)
libgraph_tool_centrality_la_SOURCES = \
graph_betweenness.cc \
graph_pagerank.cc \
graph_centrality_bind.cc \
graph_eigentrust.cc \
graph_trust_transitivity.cc \
graph_centrality_bind.cc
graph_eigenvector.cc \
graph_pagerank.cc \
graph_trust_transitivity.cc
libgraph_tool_centrality_la_include_HEADERS = \
graph_pagerank.hh \
graph_eigentrust.hh \
graph_eigenvector.hh \
graph_pagerank.hh \
graph_trust_transitivity.hh \
minmax.hh
......@@ -21,6 +21,7 @@ using namespace boost;
void export_betweenness();
void export_eigentrust();
void export_eigenvector();
void export_trust_transitivity();
void export_pagerank();
......@@ -28,6 +29,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_centrality)
{
export_betweenness();
export_eigentrust();
export_eigenvector();
export_trust_transitivity();
export_pagerank();
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007-2011 Tiago de Paula Peixoto <tiago@skewed.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 "graph.hh"
#include "graph_selectors.hh"
#include "graph_eigenvector.hh"
using namespace std;
using namespace boost;
using namespace graph_tool;
long double eigenvector(GraphInterface& g, boost::any w, boost::any c,
double epsilon, size_t max_iter)
{
if (!w.empty() && !belongs<writable_edge_scalar_properties>()(w))
throw ValueException("edge property must be writable");
if (!belongs<vertex_floating_properties>()(c))
throw ValueException("vertex property must be of floating point"
" value type");
typedef ConstantPropertyMap<int, GraphInterface::vertex_t> weight_map_t;
typedef mpl::push_back<writable_edge_scalar_properties, weight_map_t>::type
weight_props_t;
if(w.empty())
w = weight_map_t(1);
long double eig = 0;
run_action<>()
(g, bind<void>
(get_eigenvector(),
_1, g.GetVertexIndex(), g.GetEdgeIndex(), _2,
_3, epsilon, max_iter, ref(eig)),
writable_edge_scalar_properties(),
vertex_floating_properties())(w, c);
return eig;
}
void export_eigenvector()
{
using namespace boost::python;
def("get_eigenvector", &eigenvector);
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007-2011 Tiago de Paula Peixoto <tiago@skewed.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_EIGENVECTOR_HH
#define GRAPH_EIGENVECTOR_HH
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_util.hh"
#include <ext/numeric>
using __gnu_cxx::power;
namespace graph_tool
{
using namespace std;
using namespace boost;
struct get_eigenvector
{
template <class Graph, class VertexIndex, class EdgeIndex, class WeightMap,
class CentralityMap>
void operator()(Graph& g, VertexIndex vertex_index,
EdgeIndex edge_index, WeightMap w, CentralityMap c,
double epsilon, size_t max_iter, long double& eig) const
{
typedef typename property_traits<WeightMap>::value_type c_type;
typedef typename property_traits<CentralityMap>::value_type t_type;
CentralityMap c_temp(vertex_index, num_vertices(g));
// init centrality
int i, N = num_vertices(g), V = HardNumVertices()(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;
c[v] = 1.0 / V;
}
t_type norm = 0;
t_type delta = epsilon + 1;
size_t iter = 0;
while (delta >= epsilon)
{
norm = 0;
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(dynamic) reduction(+:norm)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v =
vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
c_temp[v] = 0;
typename in_edge_iteratorS<Graph>::type e, e_end;
for (tie(e, e_end) = in_edge_iteratorS<Graph>::get_edges(v, g);
e != e_end; ++e)
{
typename graph_traits<Graph>::vertex_descriptor s =
source(*e,g);
c_temp[v] += get(w, *e) * c[s];
}
norm += power(c_temp[v], 2);
}
norm = sqrt(norm);
delta = 0;
#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;
c_temp[v] /= norm;
delta += abs(c_temp[v] - c[v]);
}
swap(c_temp, c);
++iter;
if (max_iter > 0 && iter== max_iter)
break;
}
if (iter % 2 != 0)
{
#pragma omp parallel for default(shared) private(i) \
schedule(dynamic)
for (int i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v =
vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
c[v] = c_temp[v];
}
}
eig = 1. / norm;
}
};
}
#endif
......@@ -33,6 +33,7 @@ Summary
pagerank
betweenness
central_point_dominance
eigenvector
eigentrust
trust_transitivity
......@@ -48,7 +49,7 @@ import sys
import numpy
__all__ = ["pagerank", "betweenness", "central_point_dominance", "eigentrust",
"trust_transitivity"]
"eigenvector", "trust_transitivity"]
def pagerank(g, damping=0.85, pers=None, weight=None, prop=None, epsilon=1e-6,
......@@ -362,6 +363,112 @@ def central_point_dominance(g, betweenness):
_prop("v", g, betweenness))
def eigenvector(g, weight=None, vprop=None, epsilon=1e-6, max_iter=None):
r"""
Calculate the eigenvector centrality of each vertex in the graph, as well as
the largest eigenvalue.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
weights : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
Edge property map with the edge weights.
vprop : :class:`~graph_tool.PropertyMap`, optional (default: ``None``)
Vertex property map where the values of eigenvector must be stored.
epsilon : float, optional (default: ``1e-6``)
Convergence condition. The iteration will stop if the total delta of all
vertices are below this value.
max_iter : int, optional (default: ``None``)
If supplied, this will limit the total number of iterations.
Returns
-------
eigenvalue : float
The largest eigenvalue of the (weighted) adjacency matrix.
eigenvector : :class:`~graph_tool.PropertyMap`
A vertex property map containing the eigenvector values.
See Also
--------
betweenness: betweenness centrality
pagerank: PageRank centrality
trust_transitivity: pervasive trust transitivity
Notes
-----
The eigenvector centrality :math:`\mathbf{x}` is the eigenvector of the
(weighted) adjacency matrix with the largest eigenvalue :math:`\lambda`,
i.e. it is the solution of
.. math::
\mathbf{A}\mathbf{x} = \lambda\mathbf{x},
where :math:`\mathbf{A}` is the (weighted) adjacency matrix and
:math:`\lambda` is the largest eigenvalue.
The algorithm uses the power method which has a topology-dependent complexity of
:math:`O\left(N\times\frac{-\log\epsilon}{\log|\lambda_1/\lambda_2|}\right)`,
where :math:`N` is the number of vertices, :math:`\epsilon` is the ``epsilon``
parameter, and :math:`\lambda_1` and :math:`\lambda_2` are the largest and
second largest eigenvalues of the (weighted) adjacency matrix, respectively.
If enabled during compilation, this algorithm runs in parallel.
Examples
--------
>>> from numpy.random import poisson, random, seed
>>> seed(42)
>>> g = gt.random_graph(100, lambda: (poisson(3), poisson(3)))
>>> w = g.new_edge_property("double")
>>> w.a = random(g.num_edges()) * 42
>>> x = gt.eigenvector(g, w)
>>> print x[0]
0.0160851991895
>>> print x[1].a
[ 0.1376411 0.07207366 0.02727508 0.05805304 0. 0.10690994
0.04315491 0.01040908 0.02300252 0.08874163 0.04968119 0.06718114
0.05526028 0.20449371 0.02337425 0.07581173 0.19993899 0.14718912
0.08464664 0.08474977 0. 0.04843894 0. 0.0089388
0.16831573 0.00138653 0.11741616 0. 0.13455019 0.03642682
0.06729803 0.06229526 0.08937098 0.05693976 0.0793375 0.04076743
0.22176891 0.07717256 0.00518048 0.05722748 0. 0.00055799
0.04541778 0.06420469 0.06189998 0.08011859 0.05377224 0.29979873
0.01211309 0.15503588 0.02804072 0.1692873 0.01420732 0.02507
0.02959899 0.02702304 0.1652933 0.01434992 0.1073001 0.04582697
0.04618913 0.0220902 0.01421926 0.09891276 0.04522928 0.
0.00236599 0.07686829 0.03243909 0.00346715 0.1954776 0.
0.25583217 0.11710921 0.07804282 0.21188464 0.04800656 0.00321866
0.0552824 0.11204116 0.11420818 0.24071304 0.15451676 0.
0.00475456 0.10680434 0.17054333 0.18945499 0.15673649 0.03405238
0.01653319 0.02563015 0.00186129 0.12061027 0.11449362 0.11114196
0.06779788 0.00595725 0.09127559 0.02380386]
References
----------
.. [eigenvector-centrality] http://en.wikipedia.org/wiki/Centrality#Eigenvector_centrality
.. [power-method] http://en.wikipedia.org/wiki/Power_iteration
.. [langville-survey-2005] A. N. Langville, C. D. Meyer, "A Survey of
Eigenvector Methods for Web Information Retrieval", SIAM Review, vol. 47,
no. 1, pp. 135-161, 2005, :DOI:`10.1137/S0036144503424786`
"""
if vprop == None:
vprop = g.new_vertex_property("double")
if max_iter is None:
max_iter = 0
ee = libgraph_tool_centrality.\
get_eigenvector(g._Graph__graph, _prop("e", g, weight),
_prop("v", g, vprop), epsilon, max_iter)
return ee, vprop
def eigentrust(g, trust_map, vprop=None, norm=False, epsilon=1e-6, max_iter=0,
ret_iter=False):
r"""
......
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