View Javadoc
1   /*
2   * Copyright (c) 2003, The JUNG Authors
3   *
4   * All rights reserved.
5   *
6   * This software is open-source under the BSD license; see either
7   * "license.txt" or
8   * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
9   */
10  package edu.uci.ics.jung.algorithms.importance;
11  
12  import java.util.ArrayList;
13  import java.util.Collection;
14  import java.util.HashMap;
15  import java.util.LinkedList;
16  import java.util.List;
17  import java.util.Map;
18  import java.util.Queue;
19  import java.util.Stack;
20  
21  import edu.uci.ics.jung.graph.Graph;
22  import edu.uci.ics.jung.graph.UndirectedGraph;
23  
24  /**
25   * Computes betweenness centrality for each vertex and edge in the graph. The result is that each vertex
26   * and edge has a UserData element of type MutableDouble whose key is 'centrality.BetweennessCentrality'.
27   * Note: Many social network researchers like to normalize the betweenness values by dividing the values by
28   * (n-1)(n-2)/2. The values given here are unnormalized.<p>
29   *
30   * A simple example of usage is:
31   * <pre>
32   * BetweennessCentrality ranker = new BetweennessCentrality(someGraph);
33   * ranker.evaluate();
34   * ranker.printRankings();
35   * </pre>
36   *
37   * Running time is: O(n^2 + nm).
38   * @see "Ulrik Brandes: A Faster Algorithm for Betweenness Centrality. Journal of Mathematical Sociology 25(2):163-177, 2001."
39   * @author Scott White
40   * @author Tom Nelson converted to jung2
41   */
42  
43  public class BetweennessCentrality<V,E> extends AbstractRanker<V,E> {
44  
45      public static final String CENTRALITY = "centrality.BetweennessCentrality";
46  
47      /**
48       * Constructor which initializes the algorithm
49       * @param g the graph whose nodes are to be analyzed
50       */
51      public BetweennessCentrality(Graph<V,E> g) {
52          initialize(g, true, true);
53      }
54  
55      public BetweennessCentrality(Graph<V,E> g, boolean rankNodes) {
56          initialize(g, rankNodes, true);
57      }
58  
59      public BetweennessCentrality(Graph<V,E> g, boolean rankNodes, boolean rankEdges)
60      {
61          initialize(g, rankNodes, rankEdges);
62      }
63      
64  	protected void computeBetweenness(Graph<V,E> graph) {
65  
66      	Map<V,BetweennessData> decorator = new HashMap<V,BetweennessData>();
67      	Map<V,Number> bcVertexDecorator = 
68      		vertexRankScores.getUnchecked(getRankScoreKey());
69      	bcVertexDecorator.clear();
70      	Map<E,Number> bcEdgeDecorator = 
71      		edgeRankScores.getUnchecked(getRankScoreKey());
72      	bcEdgeDecorator.clear();
73          
74          Collection<V> vertices = graph.getVertices();
75          
76          for (V s : vertices) {
77  
78              initializeData(graph,decorator);
79  
80              decorator.get(s).numSPs = 1;
81              decorator.get(s).distance = 0;
82  
83              Stack<V> stack = new Stack<V>();
84              Queue<V> queue = new LinkedList<V>();
85              queue.add(s);
86  
87              while (!queue.isEmpty()) {
88                  V v = queue.remove();
89                  stack.push(v);
90  
91                  for(V w : getGraph().getSuccessors(v)) {
92  
93                      if (decorator.get(w).distance < 0) {
94                          queue.add(w);
95                          decorator.get(w).distance = decorator.get(v).distance + 1;
96                      }
97  
98                      if (decorator.get(w).distance == decorator.get(v).distance + 1) {
99                          decorator.get(w).numSPs += decorator.get(v).numSPs;
100                         decorator.get(w).predecessors.add(v);
101                     }
102                 }
103             }
104             
105             while (!stack.isEmpty()) {
106                 V w = stack.pop();
107 
108                 for (V v : decorator.get(w).predecessors) {
109 
110                     double partialDependency = (decorator.get(v).numSPs / decorator.get(w).numSPs);
111                     partialDependency *= (1.0 + decorator.get(w).dependency);
112                     decorator.get(v).dependency +=  partialDependency;
113                     E currentEdge = getGraph().findEdge(v, w);
114                     double edgeValue = bcEdgeDecorator.get(currentEdge).doubleValue();
115                     edgeValue += partialDependency;
116                     bcEdgeDecorator.put(currentEdge, edgeValue);
117                 }
118                 if (w != s) {
119                 	double bcValue = bcVertexDecorator.get(w).doubleValue();
120                 	bcValue += decorator.get(w).dependency;
121                 	bcVertexDecorator.put(w, bcValue);
122                 }
123             }
124         }
125 
126         if(graph instanceof UndirectedGraph) {
127             for (V v : vertices) { 
128             	double bcValue = bcVertexDecorator.get(v).doubleValue();
129             	bcValue /= 2.0;
130             	bcVertexDecorator.put(v, bcValue);
131             }
132             for (E e : graph.getEdges()) {
133             	double bcValue = bcEdgeDecorator.get(e).doubleValue();
134             	bcValue /= 2.0;
135             	bcEdgeDecorator.put(e, bcValue);
136             }
137         }
138 
139         for (V vertex : vertices) {
140             decorator.remove(vertex);
141         }
142     }
143 
144     private void initializeData(Graph<V,E> g, Map<V,BetweennessData> decorator) {
145         for (V vertex : g.getVertices()) {
146 
147         	Map<V,Number> bcVertexDecorator = vertexRankScores.getUnchecked(getRankScoreKey());
148         	if(bcVertexDecorator.containsKey(vertex) == false) {
149         		bcVertexDecorator.put(vertex, 0.0);
150         	}
151             decorator.put(vertex, new BetweennessData());
152         }
153         for (E e : g.getEdges()) {
154 
155         	Map<E,Number> bcEdgeDecorator = edgeRankScores.getUnchecked(getRankScoreKey());
156         	if(bcEdgeDecorator.containsKey(e) == false) {
157         		bcEdgeDecorator.put(e, 0.0);
158         	}
159         }
160     }
161     
162     /**
163      * the user datum key used to store the rank scores
164      * @return the key
165      */
166     @Override
167     public String getRankScoreKey() {
168         return CENTRALITY;
169     }
170 
171     @Override
172     public void step() {
173         computeBetweenness(getGraph());
174     }
175 
176     class BetweennessData {
177         double distance;
178         double numSPs;
179         List<V> predecessors;
180         double dependency;
181 
182         BetweennessData() {
183             distance = -1;
184             numSPs = 0;
185             predecessors = new ArrayList<V>();
186             dependency = 0;
187         }
188     }
189 }