edu.uci.ics.jung.algorithms.importance.WeightedNIPaths.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.algorithms.importance.WeightedNIPaths.java

Source

/*
* 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);
    }
}