1 /*
2 * Created on Jul 14, 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 import com.google.common.base.Functions;
16
17 import edu.uci.ics.jung.graph.Hypergraph;
18
19 /**
20 * A generalization of HITS 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' (hub or authority score)
23 * that is assigned to that vertex out of the portion that is assigned according
24 * to random jumps.
25 *
26 * @see "Algorithms for Estimating Relative Importance in Graphs by Scott White and Padhraic Smyth, 2003"
27 */
28 public class HITSWithPriors<V, E>
29 extends AbstractIterativeScorerWithPriors<V,E,HITS.Scores>
30 {
31 /**
32 * The sum of the potential, at each step, associated with vertices with no outedges (authority)
33 * or no inedges (hub).
34 */
35 protected HITS.Scores disappearing_potential;
36
37 /**
38 * Creates an instance for the specified graph, edge weights, vertex prior probabilities,
39 * and random jump probability (alpha).
40 * @param g the input graph
41 * @param edge_weights the edge weights
42 * @param vertex_priors the prior probability for each vertex
43 * @param alpha the probability of a random jump at each step
44 */
45 public HITSWithPriors(Hypergraph<V,E> g,
46 Function<E, ? extends Number> edge_weights,
47 Function<V, HITS.Scores> vertex_priors, double alpha)
48 {
49 super(g, edge_weights, vertex_priors, alpha);
50 disappearing_potential = new HITS.Scores(0,0);
51 }
52
53 /**
54 * Creates an instance for the specified graph, vertex priors, and random
55 * jump probability (alpha). The edge weights default to 1.0.
56 * @param g the input graph
57 * @param vertex_priors the prior probability for each vertex
58 * @param alpha the probability of a random jump at each step
59 */
60 public HITSWithPriors(Hypergraph<V,E> g,
61 Function<V, HITS.Scores> vertex_priors, double alpha)
62 {
63 super(g, Functions.constant(1.0), vertex_priors, alpha);
64 disappearing_potential = new HITS.Scores(0,0);
65 }
66
67 /**
68 * Updates the value for this vertex.
69 */
70 @Override
71 protected double update(V v)
72 {
73 collectDisappearingPotential(v);
74
75 double v_auth = 0;
76 for (E e : graph.getInEdges(v))
77 {
78 int incident_count = getAdjustedIncidentCount(e);
79 for (V w : graph.getIncidentVertices(e))
80 {
81 if (!w.equals(v) || hyperedges_are_self_loops)
82 v_auth += (getCurrentValue(w).hub *
83 getEdgeWeight(w,e).doubleValue() / incident_count);
84 }
85 // V w = graph.getOpposite(v, e);
86 // auth += (getCurrentValue(w).hub * getEdgeWeight(w, e).doubleValue());
87 }
88
89 double v_hub = 0;
90 for (E e : graph.getOutEdges(v))
91 {
92 int incident_count = getAdjustedIncidentCount(e);
93 for (V w : graph.getIncidentVertices(e))
94 {
95 if (!w.equals(v) || hyperedges_are_self_loops)
96 v_hub += (getCurrentValue(w).authority *
97 getEdgeWeight(w,e).doubleValue() / incident_count);
98 }
99 // V x = graph.getOpposite(v,e);
100 // hub += (getCurrentValue(x).authority * getEdgeWeight(x, e).doubleValue());
101 }
102
103 // modify total_input according to alpha
104 if (alpha > 0)
105 {
106 v_auth = v_auth * (1 - alpha) + getVertexPrior(v).authority * alpha;
107 v_hub = v_hub * (1 - alpha) + getVertexPrior(v).hub * alpha;
108 }
109 setOutputValue(v, new HITS.Scores(v_hub, v_auth));
110
111 return Math.max(Math.abs(getCurrentValue(v).hub - v_hub),
112 Math.abs(getCurrentValue(v).authority - v_auth));
113 }
114
115 /**
116 * Code which is executed after each step. In this case, deals with the
117 * 'disappearing potential', normalizes the scores, and then calls
118 * <code>super.afterStep()</code>.
119 * @see #collectDisappearingPotential(Object)
120 */
121 @Override
122 protected void afterStep()
123 {
124 if (disappearing_potential.hub > 0 || disappearing_potential.authority > 0)
125 {
126 for (V v : graph.getVertices())
127 {
128 double new_hub = getOutputValue(v).hub +
129 (1 - alpha) * (disappearing_potential.hub * getVertexPrior(v).hub);
130 double new_auth = getOutputValue(v).authority +
131 (1 - alpha) * (disappearing_potential.authority * getVertexPrior(v).authority);
132 setOutputValue(v, new HITS.Scores(new_hub, new_auth));
133 }
134 disappearing_potential.hub = 0;
135 disappearing_potential.authority = 0;
136 }
137
138 normalizeScores();
139
140 super.afterStep();
141 }
142
143 /**
144 * Normalizes scores so that sum of their squares = 1.
145 * This method may be overridden so as to yield different
146 * normalizations.
147 */
148 protected void normalizeScores() {
149 double hub_ssum = 0;
150 double auth_ssum = 0;
151 for (V v : graph.getVertices())
152 {
153 double hub_val = getOutputValue(v).hub;
154 double auth_val = getOutputValue(v).authority;
155 hub_ssum += (hub_val * hub_val);
156 auth_ssum += (auth_val * auth_val);
157 }
158
159 hub_ssum = Math.sqrt(hub_ssum);
160 auth_ssum = Math.sqrt(auth_ssum);
161
162 for (V v : graph.getVertices())
163 {
164 HITS.Scores values = getOutputValue(v);
165 setOutputValue(v, new HITS.Scores(
166 values.hub / hub_ssum,
167 values.authority / auth_ssum));
168 }
169 }
170
171 /**
172 * Collects the "disappearing potential" associated with vertices that have either
173 * no incoming edges, no outgoing edges, or both. Vertices that have no incoming edges
174 * do not directly contribute to the hub scores of other vertices; similarly, vertices
175 * that have no outgoing edges do not directly contribute to the authority scores of
176 * other vertices. These values are collected at each step and then distributed across all vertices
177 * as a part of the normalization process. (This process is not required for, and does
178 * not affect, the 'sum-of-squares'-style normalization.)
179 */
180 @Override
181 protected void collectDisappearingPotential(V v)
182 {
183 if (graph.outDegree(v) == 0)
184 {
185 if (isDisconnectedGraphOK())
186 disappearing_potential.hub += getCurrentValue(v).authority;
187 else
188 throw new IllegalArgumentException("Outdegree of " + v + " must be > 0");
189 }
190 if (graph.inDegree(v) == 0)
191 {
192 if (isDisconnectedGraphOK())
193 disappearing_potential.authority += getCurrentValue(v).hub;
194 else
195 throw new IllegalArgumentException("Indegree of " + v + " must be > 0");
196 }
197 }
198
199 }