Commit 4938eb8b authored by Tiago Peixoto's avatar Tiago Peixoto

Implement Katz centrality

parent 24a2a628
......@@ -20,6 +20,7 @@ libgraph_tool_centrality_la_SOURCES = \
graph_eigentrust.cc \
graph_eigenvector.cc \
graph_hits.cc \
graph_katz.cc \
graph_pagerank.cc \
graph_trust_transitivity.cc
......@@ -28,5 +29,6 @@ libgraph_tool_centrality_la_include_HEADERS = \
graph_eigenvector.hh \
graph_pagerank.hh \
graph_hits.hh \
graph_katz.hh \
graph_trust_transitivity.hh \
minmax.hh
......@@ -23,6 +23,7 @@ void export_betweenness();
void export_eigentrust();
void export_eigenvector();
void export_hits();
void export_katz();
void export_trust_transitivity();
void export_pagerank();
......@@ -32,6 +33,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_centrality)
export_eigentrust();
export_eigenvector();
export_hits();
export_katz();
export_trust_transitivity();
export_pagerank();
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007-2012 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_katz.hh"
using namespace std;
using namespace boost;
using namespace graph_tool;
void katz(GraphInterface& g, boost::any w, boost::any c, boost::any beta,
long double alpha, 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("centrality vertex property must be of floating point"
" value type");
if (!beta.empty() && !belongs<vertex_floating_properties>()(beta))
throw ValueException("personalization vertex property must be of floating point"
" value type");
typedef ConstantPropertyMap<int, GraphInterface::edge_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);
typedef ConstantPropertyMap<int, GraphInterface::vertex_t> beta_map_t;
typedef mpl::push_back<vertex_floating_properties, beta_map_t>::type
beta_props_t;
if(beta.empty())
beta = beta_map_t(1);
run_action<>()(g, bind<void>
(get_katz(), _1, g.GetVertexIndex(), _2,
_3, _4, alpha, epsilon, max_iter),
weight_props_t(),
vertex_floating_properties(),
beta_props_t())(w, c, beta);
}
void export_katz()
{
using namespace boost::python;
def("get_katz", &katz);
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007-2012 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_katz
{
template <class Graph, class VertexIndex, class WeightMap,
class CentralityMap, class PersonalizationMap>
void operator()(Graph& g, VertexIndex vertex_index, WeightMap w,
CentralityMap c, PersonalizationMap beta, long double alpha,
long double epsilon, size_t max_iter) 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));
t_type delta = epsilon + 1;
t_type norm = 0;
size_t iter = 0;
int i, N = num_vertices(g);
while (delta >= epsilon)
{
norm = 0;
#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] = get(beta, v);
typename in_or_out_edge_iteratorS<Graph>::type e, e_end;
for (tie(e, e_end) = in_or_out_edge_iteratorS<Graph>::get_edges(v, g);
e != e_end; ++e)
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(*e,g);
else
s = target(*e,g);
c_temp[v] += alpha * 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 (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];
}
}
}
};
}
#endif
......@@ -34,6 +34,7 @@ Summary
betweenness
central_point_dominance
eigenvector
katz
hits
eigentrust
trust_transitivity
......@@ -52,7 +53,7 @@ import sys
import numpy
__all__ = ["pagerank", "betweenness", "central_point_dominance", "eigentrust",
"eigenvector", "hits", "trust_transitivity"]
"eigenvector", "katz", "hits", "trust_transitivity"]
def pagerank(g, damping=0.85, pers=None, weight=None, prop=None, epsilon=1e-6,
......@@ -469,6 +470,122 @@ def eigenvector(g, weight=None, vprop=None, epsilon=1e-6, max_iter=None):
return ee, vprop
def katz(g, alpha=0.01, beta=None, 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.
weight : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
Edge property map with the edge weights.
alpha : float, optional (default: ``0.01``)
Free parameter :math:`\alpha`. This must be smaller than the largest
eigenvalue of the adjacency matrix.
beta : :class:`~graph_tool.PropertyMap`, optional (default: ``None``)
Vertex property map where the local personalization values. If not
provided, the global value of 1 will be used.
vprop : :class:`~graph_tool.PropertyMap`, optional (default: ``None``)
Vertex property map where the values of eigenvector must be stored. If
provided, it will be used uninitialized.
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
-------
centrality : :class:`~graph_tool.PropertyMap`
A vertex property map containing the Katz centrality values.
See Also
--------
betweenness: betweenness centrality
pagerank: PageRank centrality
eigenvector: eigenvector centrality
hits: hubs and authority centralities
trust_transitivity: pervasive trust transitivity
Notes
-----
The Katz centrality :math:`\mathbf{x}` is the solution of the nonhomogeneous
linear system
.. math::
\mathbf{x} = \alpha\mathbf{A}\mathbf{x} + \mathbf{\beta},
where :math:`\mathbf{A}` is the (weighted) adjacency matrix and
:math:`\mathbf{\beta}` is the personalization vector (if not supplied,
:math:`\mathbf{\beta} = \mathbf{1}` is assumed).
The algorithm uses successive iterations of the equation above, which has a
topology-dependent convergence complexity.
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
>>> beta = g.new_vertex_property("double")
>>> beta.a = random(g.num_vertices())
>>> x = gt.katz(g, 1.2, beta, w)
>>> print(x.a)
[ 1.37641115e-01 7.20736590e-02 2.72750802e-02 5.80530330e-02
2.01730812e-46 1.06909945e-01 4.31549123e-02 1.04090757e-02
2.30025193e-02 8.87416158e-02 4.96811868e-02 6.71811510e-02
5.52602884e-02 2.04493707e-01 2.33742500e-02 7.58117387e-02
1.99938991e-01 1.47189139e-01 8.46466442e-02 8.47497818e-02
1.51237905e-45 4.84389342e-02 5.44009790e-46 8.93879711e-03
1.68315739e-01 1.38653230e-03 1.17416178e-01 5.86769582e-45
1.34550186e-01 3.64268155e-02 6.72980215e-02 6.22952571e-02
8.93709730e-02 5.69397613e-02 7.93375017e-02 4.07674261e-02
2.21768916e-01 7.71725431e-02 5.18047531e-03 5.72274765e-02
3.24137925e-46 5.57993342e-04 4.54177794e-02 6.42046867e-02
6.18999821e-02 8.01185834e-02 5.37722396e-02 2.99798712e-01
1.21130890e-02 1.55035898e-01 2.80407226e-02 1.69287315e-01
1.42073265e-02 2.50699989e-02 2.95989919e-02 2.70230452e-02
1.65293284e-01 1.43499144e-02 1.07300107e-01 4.58269685e-02
4.61891303e-02 2.20902054e-02 1.42192559e-02 9.89127698e-02
4.52292816e-02 5.19593979e-46 2.36598546e-03 7.68682863e-02
3.24390891e-02 3.46714702e-03 1.95477600e-01 6.54634726e-46
2.55832162e-01 1.17109207e-01 7.80428298e-02 2.11884617e-01
4.80065642e-02 3.21866466e-03 5.52824029e-02 1.12041157e-01
1.14208195e-01 2.40713033e-01 1.54516765e-01 2.03810664e-46
4.75455657e-03 1.06804336e-01 1.70543325e-01 1.89454987e-01
1.56736484e-01 3.40523749e-02 1.65331867e-02 2.56301436e-02
1.86129309e-03 1.20610273e-01 1.14493631e-01 1.11141961e-01
6.77978870e-02 5.95724763e-03 9.12755850e-02 2.38038610e-02]
References
----------
.. [katz-centrality] http://en.wikipedia.org/wiki/Katz_centrality
.. [katz-new] L. Katz, "A new status index derived from sociometric analysis",
Psychometrika 18, Number 1, 39-43, 1953, :DOI:`10.1007/BF02289026`
"""
if vprop == None:
vprop = g.new_vertex_property("double")
N = len(vprop.a)
vprop.a = beta.a[:N] if beta is not None else 1.
if max_iter is None:
max_iter = 0
ee = libgraph_tool_centrality.\
get_katz(g._Graph__graph, _prop("e", g, weight), _prop("v", g, vprop),
_prop("v", beta, vprop), float(alpha), epsilon, max_iter)
return vprop
def hits(g, weight=None, xprop=None, yprop=None, epsilon=1e-6, max_iter=None):
r"""
Calculate the authority and hub centralities of each vertex in the graph.
......
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