1 /*
2 * Created on Jul 6, 2007
3 *
4 * Copyright (c) 2007, The JUNG Authors
5 *
6 * All rights reserved.
7 *
8 * This software is open-source under the BSD license; see either
9 * "license.txt" or
10 * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
11 */
12 package edu.uci.ics.jung.algorithms.scoring;
13
14 import com.google.common.base.Function;
15
16 import edu.uci.ics.jung.algorithms.scoring.util.UniformDegreeWeight;
17 import edu.uci.ics.jung.graph.Hypergraph;
18
19 /**
20 * A generalization of PageRank that permits non-uniformly-distributed random jumps.
21 * The 'vertex_priors' (that is, prior probabilities for each vertex) may be
22 * thought of as the fraction of the total 'potential' that is assigned to that
23 * vertex at each step out of the portion that is assigned according
24 * to random jumps (this portion is specified by 'alpha').
25 *
26 * @see "Algorithms for Estimating Relative Importance in Graphs by Scott White and Padhraic Smyth, 2003"
27 * @see PageRank
28 */
29 public class PageRankWithPriors<V, E>
30 extends AbstractIterativeScorerWithPriors<V,E,Double>
31 {
32 /**
33 * Maintains the amount of potential associated with vertices with no out-edges.
34 */
35 protected double disappearing_potential = 0.0;
36
37 /**
38 * Creates an instance with the specified graph, edge weights, vertex priors, and
39 * 'random jump' probability (alpha).
40 * @param graph the input graph
41 * @param edge_weights the edge weights, denoting transition probabilities from source to destination
42 * @param vertex_priors the prior probabilities for each vertex
43 * @param alpha the probability of executing a 'random jump' at each step
44 */
45 public PageRankWithPriors(Hypergraph<V,E> graph,
46 Function<E, ? extends Number> edge_weights,
47 Function<V, Double> vertex_priors, double alpha)
48 {
49 super(graph, edge_weights, vertex_priors, alpha);
50 }
51
52 /**
53 * Creates an instance with the specified graph, vertex priors, and
54 * 'random jump' probability (alpha). The outgoing edge weights for each
55 * vertex will be equal and sum to 1.
56 * @param graph the input graph
57 * @param vertex_priors the prior probabilities for each vertex
58 * @param alpha the probability of executing a 'random jump' at each step
59 */
60 public PageRankWithPriors(Hypergraph<V,E> graph,
61 Function<V, Double> vertex_priors, double alpha)
62 {
63 super(graph, vertex_priors, alpha);
64 this.edge_weights = new UniformDegreeWeight<V,E>(graph);
65 }
66
67 /**
68 * Updates the value for this vertex. Called by <code>step()</code>.
69 */
70 @Override
71 public double update(V v)
72 {
73 collectDisappearingPotential(v);
74
75 double v_input = 0;
76 for (E e : graph.getInEdges(v))
77 {
78 // For graphs, the code below is equivalent to
79 // V w = graph.getOpposite(v, e);
80 // total_input += (getCurrentValue(w) * getEdgeWeight(w,e).doubleValue());
81 // For hypergraphs, this divides the potential coming from w
82 // by the number of vertices in the connecting edge e.
83 int incident_count = getAdjustedIncidentCount(e);
84 for (V w : graph.getIncidentVertices(e))
85 {
86 if (!w.equals(v) || hyperedges_are_self_loops)
87 v_input += (getCurrentValue(w) *
88 getEdgeWeight(w,e).doubleValue() / incident_count);
89 }
90 }
91
92 // modify total_input according to alpha
93 double new_value = alpha > 0 ?
94 v_input * (1 - alpha) + getVertexPrior(v) * alpha :
95 v_input;
96 setOutputValue(v, new_value);
97
98 return Math.abs(getCurrentValue(v) - new_value);
99 }
100
101 /**
102 * Cleans up after each step. In this case that involves allocating the disappearing
103 * potential (thus maintaining normalization of the scores) according to the vertex
104 * probability priors, and then calling
105 * <code>super.afterStep</code>.
106 */
107 @Override
108 protected void afterStep()
109 {
110 // distribute disappearing potential according to priors
111 if (disappearing_potential > 0)
112 {
113 for (V v : graph.getVertices())
114 {
115 setOutputValue(v, getOutputValue(v) +
116 (1 - alpha) * (disappearing_potential * getVertexPrior(v)));
117 }
118 disappearing_potential = 0;
119 }
120
121 super.afterStep();
122 }
123
124 /**
125 * Collects the "disappearing potential" associated with vertices that have
126 * no outgoing edges. Vertices that have no outgoing edges do not directly
127 * contribute to the scores of other vertices. These values are collected
128 * at each step and then distributed across all vertices
129 * as a part of the normalization process.
130 */
131 @Override
132 protected void collectDisappearingPotential(V v)
133 {
134 if (graph.outDegree(v) == 0)
135 {
136 if (isDisconnectedGraphOK())
137 disappearing_potential += getCurrentValue(v);
138 else
139 throw new IllegalArgumentException("Outdegree of " + v + " must be > 0");
140 }
141 }
142 }