Skip to content

Commit

Permalink
Merge pull request #1360 from Scinawa/harmonic
Browse files Browse the repository at this point in the history
Added Harmonic Centrality Algorithm
  • Loading branch information
chebee7i committed Feb 28, 2015
2 parents cded585 + f9175d3 commit 9f54f6d
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 22 deletions.
3 changes: 3 additions & 0 deletions doc/source/reference/api_2.0.rst
Expand Up @@ -60,6 +60,9 @@ New functionalities
* [`#1338 <https://github.com/networkx/networkx/pull/1338>`_]
Added support for finding optimum branchings and arborescences.

* [`#1360 <https://github.com/networkx/networkx/pull/1360>`_]
Added harmonic centrality to ``network.algorithms.centrality``.

Removed functionalities
-----------------------

Expand Down
35 changes: 13 additions & 22 deletions networkx/algorithms/centrality/__init__.py
@@ -1,22 +1,13 @@
from networkx.algorithms.centrality.betweenness import *
from networkx.algorithms.centrality.betweenness_subset import *
from networkx.algorithms.centrality.closeness import *
from networkx.algorithms.centrality.current_flow_closeness import *
from networkx.algorithms.centrality.current_flow_betweenness import *
from networkx.algorithms.centrality.current_flow_betweenness_subset import *
from networkx.algorithms.centrality.degree_alg import *
from networkx.algorithms.centrality.dispersion import *
from networkx.algorithms.centrality.eigenvector import *
from networkx.algorithms.centrality.katz import *
from networkx.algorithms.centrality.load import *
from networkx.algorithms.centrality.communicability_alg import *
import networkx.algorithms.centrality.betweenness
import networkx.algorithms.centrality.closeness
import networkx.algorithms.centrality.current_flow_betweenness
import networkx.algorithms.centrality.current_flow_closeness
import networkx.algorithms.centrality.degree_alg
import networkx.algorithms.centrality.dispersion
import networkx.algorithms.centrality.eigenvector
import networkx.algorithms.centrality.load
import networkx.algorithms.centrality.communicability_alg
import networkx.algorithms.centrality.katz
from .betweenness import *
from .betweenness_subset import *
from .closeness import *
from .communicability_alg import *
from .current_flow_closeness import *
from .current_flow_betweenness import *
from .current_flow_betweenness_subset import *
from .degree_alg import *
from .dispersion import *
from .eigenvector import *
from .harmonic import *
from .katz import *
from .load import *
84 changes: 84 additions & 0 deletions networkx/algorithms/centrality/harmonic.py
@@ -0,0 +1,84 @@
"""
Harmonic centrality measure.
"""
# Copyright (C) 2004-2015 by
# Alessandro Luongo
# BSD license.
from __future__ import division
import functools
import networkx as nx


__author__ = "\n".join(['Alessandro Luongo (alessandro.luongo@studenti.unimi.it'])
__all__ = ['harmonic_centrality']


def harmonic_centrality(G, distance=None):
r"""Compute harmonic centrality for nodes.
Harmonic centrality [1] of a node `u` is the sum of the reciprocal of the
nonzero shortest paths from all other nodes.
.. math::
C(u) = \sum_{v=1}^{n-1} \frac{1}{d(v, u)},
where `d(v, u)` is the shortest-path distance between `v` and `u`,
and `n` is the number of nodes in the graph.
Notice that higher values indicate higher centrality.
Parameters
----------
G : graph
A NetworkX graph.
distance : edge attribute key, optional (default=None)
Use the specified edge attribute as the edge distance in shortest path
calculations. If `None`, then each edge will have distance equal to 1.
Returns
-------
nodes : dictionary
Dictionary of nodes with harmonic centrality as the value.
See Also
--------
betweenness_centrality, load_centrality, eigenvector_centrality,
degree_centrality, closeness_centrality
Notes
-----
If the 'distance' keyword is set to an edge attribute key then the
shortest-path length will be computed using Dijkstra's algorithm with
that edge attribute as the edge weight.
References
----------
.. [1] Boldi, Paolo, and Sebastiano Vigna. "Axioms for centrality."
Internet Mathematics 10.3-4 (2014): 222-262.
"""

if distance is not None:
# use Dijkstra's algorithm with specified attribute as edge weight
path_length = functools.partial(nx.all_pairs_dijkstra_path_length,
weight=distance)
else:
path_length = nx.all_pairs_shortest_path_length

nodes = G.nodes()
harmonic_centrality = {}

if len(G) <= 1:
for singleton in nodes:
harmonic_centrality[singleton] = 0.0
return harmonic_centrality

sp = path_length(G.reverse() if G.is_directed() else G)

for n in nodes:
harmonic_centrality[n] = sum([1/i if i > 0 else 0
for i in sp[n].values()])

return harmonic_centrality


129 changes: 129 additions & 0 deletions networkx/algorithms/centrality/tests/test_harmonic_centrality.py
@@ -0,0 +1,129 @@
"""
Tests for degree centrality.
"""
from nose.tools import *
import networkx as nx
from networkx.algorithms.centrality import harmonic_centrality

class TestClosenessCentrality:
def setUp(self):
self.P3 = nx.path_graph(3)
self.P4 = nx.path_graph(4)
self.K5 = nx.complete_graph(5)

self.C4 = nx.cycle_graph(4)
self.C5 = nx.cycle_graph(5)


self.T = nx.balanced_tree(r=2, h=2)

self.Gb = nx.DiGraph()
self.Gb.add_edges_from([(0, 1), (0, 2), (0, 4), (2, 1),
(2, 3), (4, 3)])


def test_p3_harmonic(self):
c = harmonic_centrality(self.P3)
d = {0: 1.5,
1: 2,
2: 1.5}
for n in sorted(self.P3):
assert_almost_equal(c[n], d[n], places=3)


def test_p4_harmonic(self):
c = harmonic_centrality(self.P4)
d = {0: 1.8333333,
1: 2.5,
2: 2.5,
3: 1.8333333}
for n in sorted(self.P4):
assert_almost_equal(c[n], d[n], places=3)


def test_clique_complete(self):
c = harmonic_centrality(self.K5)
d = {0: 4,
1: 4,
2: 4,
3: 4,
4: 4}
for n in sorted(self.P3):
assert_almost_equal(c[n], d[n],places=3)


def test_cycle_C4(self):
c = harmonic_centrality(self.C4)
d = {0: 2.5,
1: 2.5,
2: 2.5,
3: 2.5,}
for n in sorted(self.C4):
assert_almost_equal(c[n], d[n], places=3)


def test_cycle_C5(self):
c = harmonic_centrality(self.C5)
d={0: 3,
1: 3,
2: 3,
3: 3,
4: 3,
5: 4}
for n in sorted(self.C5):
assert_almost_equal(c[n], d[n], places=3)


def test_bal_tree(self):
c = harmonic_centrality(self.T)
d = {0: 4.0,
1: 4.1666,
2: 4.1666,
3: 2.8333,
4: 2.8333,
5: 2.8333,
6: 2.8333}
for n in sorted(self.T):
assert_almost_equal(c[n], d[n], places=3)


def test_exampleGraph(self):
c = harmonic_centrality(self.Gb)
d = {0: 0,
1: 2,
2: 1,
3: 2.5,
4: 1}
for n in sorted(self.Gb):
assert_almost_equal(c[n], d[n], places=3)


def test_weighted_harmonic(self):
XG = nx.DiGraph()
XG.add_weighted_edges_from([('a','b',10), ('d','c',5), ('a','c',1),
('e','f',2), ('f','c',1), ('a','f',3),
])
c = harmonic_centrality(XG, distance='weight')
d = {'a': 0,
'b': 0.1,
'c': 2.533,
'd': 0,
'e': 0,
'f': 0.83333}
for n in sorted(XG):
assert_almost_equal(c[n], d[n], places=3)


def test_empty(self):
G = nx.DiGraph()
c = harmonic_centrality(G, distance='weight')
d = {}
assert_equal(c, d)


def test_singleton(self):
G = nx.DiGraph()
G.add_node(0)
c = harmonic_centrality(G, distance='weight')
d = {0: 0}
assert_equal(c, d)

0 comments on commit 9f54f6d

Please sign in to comment.