--- /dev/null
+/*
+* Copyright (c) 2003, the JUNG Project and the Regents of the University
+* of California
+* All rights reserved.
+*
+* This software is open-source under the BSD license; see either
+* "license.txt" or
+* http://jung.sourceforge.net/license.txt for a description.
+*/
+package edu.uci.ics.jung.algorithms.importance;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.apache.commons.collections15.Buffer;
+import org.apache.commons.collections15.buffer.UnboundedFifoBuffer;
+
+import edu.uci.ics.jung.graph.Graph;
+import edu.uci.ics.jung.graph.UndirectedGraph;
+
+/**
+ * Computes betweenness centrality for each vertex and edge in the graph. The result is that each vertex
+ * and edge has a UserData element of type MutableDouble whose key is 'centrality.BetweennessCentrality'.
+ * Note: Many social network researchers like to normalize the betweenness values by dividing the values by
+ * (n-1)(n-2)/2. The values given here are unnormalized.<p>
+ *
+ * A simple example of usage is:
+ * <pre>
+ * BetweennessCentrality ranker = new BetweennessCentrality(someGraph);
+ * ranker.evaluate();
+ * ranker.printRankings();
+ * </pre>
+ *
+ * Running time is: O(n^2 + nm).
+ * @see "Ulrik Brandes: A Faster Algorithm for Betweenness Centrality. Journal of Mathematical Sociology 25(2):163-177, 2001."
+ * @author Scott White
+ * @author Tom Nelson converted to jung2
+ */
+
+public class BetweennessCentrality<V,E> extends AbstractRanker<V,E> {
+
+ public static final String CENTRALITY = "centrality.BetweennessCentrality";
+
+ /**
+ * Constructor which initializes the algorithm
+ * @param g the graph whose nodes are to be analyzed
+ */
+ public BetweennessCentrality(Graph<V,E> g) {
+ initialize(g, true, true);
+ }
+
+ public BetweennessCentrality(Graph<V,E> g, boolean rankNodes) {
+ initialize(g, rankNodes, true);
+ }
+
+ public BetweennessCentrality(Graph<V,E> g, boolean rankNodes, boolean rankEdges)
+ {
+ initialize(g, rankNodes, rankEdges);
+ }
+
+ protected void computeBetweenness(Graph<V,E> graph) {
+
+ Map<V,BetweennessData> decorator = new HashMap<V,BetweennessData>();
+ Map<V,Number> bcVertexDecorator =
+ vertexRankScores.get(getRankScoreKey());
+ bcVertexDecorator.clear();
+ Map<E,Number> bcEdgeDecorator =
+ edgeRankScores.get(getRankScoreKey());
+ bcEdgeDecorator.clear();
+
+ Collection<V> vertices = graph.getVertices();
+
+ for (V s : vertices) {
+
+ initializeData(graph,decorator);
+
+ decorator.get(s).numSPs = 1;
+ decorator.get(s).distance = 0;
+
+ Stack<V> stack = new Stack<V>();
+ Buffer<V> queue = new UnboundedFifoBuffer<V>();
+ queue.add(s);
+
+ while (!queue.isEmpty()) {
+ V v = queue.remove();
+ stack.push(v);
+
+ for(V w : getGraph().getSuccessors(v)) {
+
+ if (decorator.get(w).distance < 0) {
+ queue.add(w);
+ decorator.get(w).distance = decorator.get(v).distance + 1;
+ }
+
+ if (decorator.get(w).distance == decorator.get(v).distance + 1) {
+ decorator.get(w).numSPs += decorator.get(v).numSPs;
+ decorator.get(w).predecessors.add(v);
+ }
+ }
+ }
+
+ while (!stack.isEmpty()) {
+ V w = stack.pop();
+
+ for (V v : decorator.get(w).predecessors) {
+
+ double partialDependency = (decorator.get(v).numSPs / decorator.get(w).numSPs);
+ partialDependency *= (1.0 + decorator.get(w).dependency);
+ decorator.get(v).dependency += partialDependency;
+ E currentEdge = getGraph().findEdge(v, w);
+ double edgeValue = bcEdgeDecorator.get(currentEdge).doubleValue();
+ edgeValue += partialDependency;
+ bcEdgeDecorator.put(currentEdge, edgeValue);
+ }
+ if (w != s) {
+ double bcValue = bcVertexDecorator.get(w).doubleValue();
+ bcValue += decorator.get(w).dependency;
+ bcVertexDecorator.put(w, bcValue);
+ }
+ }
+ }
+
+ if(graph instanceof UndirectedGraph) {
+ for (V v : vertices) {
+ double bcValue = bcVertexDecorator.get(v).doubleValue();
+ bcValue /= 2.0;
+ bcVertexDecorator.put(v, bcValue);
+ }
+ for (E e : graph.getEdges()) {
+ double bcValue = bcEdgeDecorator.get(e).doubleValue();
+ bcValue /= 2.0;
+ bcEdgeDecorator.put(e, bcValue);
+ }
+ }
+
+ for (V vertex : vertices) {
+ decorator.remove(vertex);
+ }
+ }
+
+ private void initializeData(Graph<V,E> g, Map<V,BetweennessData> decorator) {
+ for (V vertex : g.getVertices()) {
+
+ Map<V,Number> bcVertexDecorator = vertexRankScores.get(getRankScoreKey());
+ if(bcVertexDecorator.containsKey(vertex) == false) {
+ bcVertexDecorator.put(vertex, 0.0);
+ }
+ decorator.put(vertex, new BetweennessData());
+ }
+ for (E e : g.getEdges()) {
+
+ Map<E,Number> bcEdgeDecorator = edgeRankScores.get(getRankScoreKey());
+ if(bcEdgeDecorator.containsKey(e) == false) {
+ bcEdgeDecorator.put(e, 0.0);
+ }
+ }
+ }
+
+ /**
+ * the user datum key used to store the rank scores
+ * @return the key
+ */
+ @Override
+ public String getRankScoreKey() {
+ return CENTRALITY;
+ }
+
+ @Override
+ public void step() {
+ computeBetweenness(getGraph());
+ }
+
+ class BetweennessData {
+ double distance;
+ double numSPs;
+ List<V> predecessors;
+ double dependency;
+
+ BetweennessData() {
+ distance = -1;
+ numSPs = 0;
+ predecessors = new ArrayList<V>();
+ dependency = 0;
+ }
+ }
+}