/* * Created on Jul 6, 2007 * * Copyright (c) 2007, 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.scoring; import org.apache.commons.collections15.Transformer; import edu.uci.ics.jung.algorithms.scoring.util.UniformDegreeWeight; import edu.uci.ics.jung.graph.Hypergraph; /** * A generalization of PageRank that permits non-uniformly-distributed random * jumps. The 'vertex_priors' (that is, prior probabilities for each vertex) may * be thought of as the fraction of the total 'potential' that is assigned to * that vertex at each step out of the portion that is assigned according to * random jumps (this portion is specified by 'alpha'). * * @see "Algorithms for Estimating Relative Importance in Graphs by Scott White and Padhraic Smyth, 2003" * @see PageRank */ public class PageRankWithPriors<V, E> extends AbstractIterativeScorerWithPriors<V, E, Double> { /** * Maintains the amount of potential associated with vertices with no * out-edges. */ protected double disappearing_potential = 0.0; /** * Creates an instance with the specified graph, edge weights, vertex * priors, and 'random jump' probability (alpha). * * @param graph * the input graph * @param edge_weights * the edge weights, denoting transition probabilities from * source to destination * @param vertex_priors * the prior probabilities for each vertex * @param alpha * the probability of executing a 'random jump' at each step */ public PageRankWithPriors(Hypergraph<V, E> graph, Transformer<E, ? extends Number> edge_weights, Transformer<V, Double> vertex_priors, double alpha) { super(graph, edge_weights, vertex_priors, alpha); } /** * Creates an instance with the specified graph, vertex priors, and 'random * jump' probability (alpha). The outgoing edge weights for each vertex will * be equal and sum to 1. * * @param graph * the input graph * @param vertex_priors * the prior probabilities for each vertex * @param alpha * the probability of executing a 'random jump' at each step */ public PageRankWithPriors(Hypergraph<V, E> graph, Transformer<V, Double> vertex_priors, double alpha) { super(graph, vertex_priors, alpha); this.edge_weights = new UniformDegreeWeight<V, E>(graph); } /** * Updates the value for this vertex. Called by <code>step()</code>. */ @Override public double update(V v) { collectDisappearingPotential(v); double v_input = 0; for (E e : graph.getInEdges(v)) { // For graphs, the code below is equivalent to // V w = graph.getOpposite(v, e); // total_input += (getCurrentValue(w) * // getEdgeWeight(w,e).doubleValue()); // For hypergraphs, this divides the potential coming from w // by the number of vertices in the connecting edge e. int incident_count = getAdjustedIncidentCount(e); for (V w : graph.getIncidentVertices(e)) { if (!w.equals(v) || hyperedges_are_self_loops) { v_input += (getCurrentValue(w) * getEdgeWeight(w, e).doubleValue() / incident_count); } } } // modify total_input according to alpha double new_value = alpha > 0 ? v_input * (1 - alpha) + getVertexPrior(v) * alpha : v_input; setOutputValue(v, new_value); return Math.abs(getCurrentValue(v) - new_value); } /** * Cleans up after each step. In this case that involves allocating the * disappearing potential (thus maintaining normalization of the scores) * according to the vertex probability priors, and then calling * <code>super.afterStep</code>. */ @Override protected void afterStep() { // distribute disappearing potential according to priors if (disappearing_potential > 0) { for (V v : graph.getVertices()) { setOutputValue(v, getOutputValue(v) + (1 - alpha) * (disappearing_potential * getVertexPrior(v))); } disappearing_potential = 0; } super.afterStep(); } /** * Collects the "disappearing potential" associated with vertices that have * no outgoing edges. Vertices that have no outgoing edges do not directly * contribute to the scores of other vertices. These values are collected at * each step and then distributed across all vertices as a part of the * normalization process. */ @Override protected void collectDisappearingPotential(V v) { if (graph.outDegree(v) == 0) { if (isDisconnectedGraphOK()) { disappearing_potential += getCurrentValue(v); } else { throw new IllegalArgumentException( "Outdegree of " + v + " must be > 0"); } } } }