Java tutorial
/* * 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.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections15.Factory; import edu.uci.ics.jung.graph.DirectedGraph; /** * This algorithm measures the importance of nodes based upon both the number and length of disjoint paths that lead * to a given node from each of the nodes in the root set. Specifically the formula for measuring the importance of a * node is given by: I(t|R) = sum_i=1_|P(r,t)|_{alpha^|p_i|} where alpha is the path decay coefficient, p_i is path i * and P(r,t) is a set of maximum-sized node-disjoint paths from r to t. * <p> * This algorithm uses heuristic breadth-first search to try and find the maximum-sized set of node-disjoint paths * between two nodes. As such, it is not guaranteed to give exact answers. * <p> * A simple example of usage is: * <pre> * WeightedNIPaths ranker = new WeightedNIPaths(someGraph,2.0,6,rootSet); * ranker.evaluate(); * ranker.printRankings(); * </pre> * * @author Scott White * @see "Algorithms for Estimating Relative Importance in Graphs by Scott White and Padhraic Smyth, 2003" */ public class WeightedNIPaths<V, E> extends AbstractRanker<V, E> { public final static String WEIGHTED_NIPATHS_KEY = "jung.algorithms.importance.WEIGHTED_NIPATHS_KEY"; private double mAlpha; private int mMaxDepth; private Set<V> mPriors; private Map<E, Number> pathIndices = new HashMap<E, Number>(); private Map<Object, V> roots = new HashMap<Object, V>(); private Map<V, Set<Number>> pathsSeenMap = new HashMap<V, Set<Number>>(); private Factory<V> vertexFactory; private Factory<E> edgeFactory; /** * Constructs and initializes the algorithm. * @param graph the graph whose nodes are being measured for their importance * @param alpha the path decay coefficient (>= 1); 2 is recommended * @param maxDepth the maximal depth to search out from the root set * @param priors the root set (starting vertices) */ public WeightedNIPaths(DirectedGraph<V, E> graph, Factory<V> vertexFactory, Factory<E> edgeFactory, double alpha, int maxDepth, Set<V> priors) { super.initialize(graph, true, false); this.vertexFactory = vertexFactory; this.edgeFactory = edgeFactory; mAlpha = alpha; mMaxDepth = maxDepth; mPriors = priors; for (V v : graph.getVertices()) { super.setVertexRankScore(v, 0.0); } } protected void incrementRankScore(V v, double rankValue) { setVertexRankScore(v, getVertexRankScore(v) + rankValue); } protected void computeWeightedPathsFromSource(V root, int depth) { int pathIdx = 1; for (E e : getGraph().getOutEdges(root)) { this.pathIndices.put(e, pathIdx); this.roots.put(e, root); newVertexEncountered(pathIdx, getGraph().getEndpoints(e).getSecond(), root); pathIdx++; } List<E> edges = new ArrayList<E>(); V virtualNode = vertexFactory.create(); getGraph().addVertex(virtualNode); E virtualSinkEdge = edgeFactory.create(); getGraph().addEdge(virtualSinkEdge, virtualNode, root); edges.add(virtualSinkEdge); int currentDepth = 0; while (currentDepth <= depth) { double currentWeight = Math.pow(mAlpha, -1.0 * currentDepth); for (E currentEdge : edges) { incrementRankScore(getGraph().getEndpoints(currentEdge).getSecond(), // currentWeight); } if ((currentDepth == depth) || (edges.size() == 0)) break; List<E> newEdges = new ArrayList<E>(); for (E currentSourceEdge : edges) { //Iterator sourceEdgeIt = edges.iterator(); sourceEdgeIt.hasNext();) { Number sourcePathIndex = this.pathIndices.get(currentSourceEdge); // from the currentSourceEdge, get its opposite end // then iterate over the out edges of that opposite end V newDestVertex = getGraph().getEndpoints(currentSourceEdge).getSecond(); Collection<E> outs = getGraph().getOutEdges(newDestVertex); for (E currentDestEdge : outs) { V destEdgeRoot = this.roots.get(currentDestEdge); V destEdgeDest = getGraph().getEndpoints(currentDestEdge).getSecond(); if (currentSourceEdge == virtualSinkEdge) { newEdges.add(currentDestEdge); continue; } if (destEdgeRoot == root) { continue; } if (destEdgeDest == getGraph().getEndpoints(currentSourceEdge).getFirst()) {//currentSourceEdge.getSource()) { continue; } Set<Number> pathsSeen = this.pathsSeenMap.get(destEdgeDest); if (pathsSeen == null) { newVertexEncountered(sourcePathIndex.intValue(), destEdgeDest, root); } else if (roots.get(destEdgeDest) != root) { roots.put(destEdgeDest, root); pathsSeen.clear(); pathsSeen.add(sourcePathIndex); } else if (!pathsSeen.contains(sourcePathIndex)) { pathsSeen.add(sourcePathIndex); } else { continue; } this.pathIndices.put(currentDestEdge, sourcePathIndex); this.roots.put(currentDestEdge, root); newEdges.add(currentDestEdge); } } edges = newEdges; currentDepth++; } getGraph().removeVertex(virtualNode); } private void newVertexEncountered(int sourcePathIndex, V dest, V root) { Set<Number> pathsSeen = new HashSet<Number>(); pathsSeen.add(sourcePathIndex); this.pathsSeenMap.put(dest, pathsSeen); roots.put(dest, root); } @Override public void step() { for (V v : mPriors) { computeWeightedPathsFromSource(v, mMaxDepth); } normalizeRankings(); // return 0; } /** * Given a node, returns the corresponding rank score. This implementation of <code>getRankScore</code> assumes * the decoration representing the rank score is of type <code>MutableDouble</code>. * @return the rank score for this node */ @Override public String getRankScoreKey() { return WEIGHTED_NIPATHS_KEY; } @Override protected void onFinalize(Object udc) { pathIndices.remove(udc); roots.remove(udc); pathsSeenMap.remove(udc); } }