File Coverage

blib/lib/Graph/Centrality/Pagerank.pm
Criterion Covered Total %
statement 189 203 93.1
branch 74 126 58.7
condition 10 15 66.6
subroutine 15 15 100.0
pod 2 2 100.0
total 290 361 80.3


line stmt bran cond sub pod time code
1             package Graph::Centrality::Pagerank;
2              
3             require 5.006_000;
4 1     1   34916 use strict;
  1         3  
  1         38  
5 1     1   5 use warnings;
  1         3  
  1         29  
6 1     1   1303 use Graph;
  1         196677  
  1         35  
7 1     1   1536 use Data::Dump qw(dump);
  1         5010  
  1         93  
8              
9             BEGIN {
10 1     1   8 use Exporter ();
  1         1  
  1         20  
11 1     1   4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         2  
  1         97  
12 1     1   2 $VERSION = '1.05';
13 1         18 @ISA = qw(Exporter);
14 1         2 @EXPORT = qw();
15 1         2 @EXPORT_OK = qw();
16 1         1993 %EXPORT_TAGS = ();
17             }
18              
19             =head1 NAME
20              
21             C - Computes pagerank of all nodes in a graph.
22              
23             =head1 SYNOPSIS
24              
25             use Graph::Centrality::Pagerank;
26             use Data::Dump qw(dump);
27             my $ranker = Graph::Centrality::Pagerank->new();
28             my $listOfEdges = [[1,2],[3,4]];
29             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges);
30             # dumps:
31             # {
32             # 1 => "0.175438596989046",
33             # 2 => "0.324561403010954",
34             # 3 => "0.175438596989046",
35             # 4 => "0.324561403010954",
36             # }
37              
38             =head1 DESCRIPTION
39              
40             C computes the pagerank of the all nodes in a graph.
41             The input can be a list of edges or a L. C is
42             written entirely in Perl and is not recommended for use in high performance applications.
43              
44             =head1 CONSTRUCTOR
45              
46             =head2 C
47              
48             The method C creates an instance of the C
49             class with the following parameters:
50              
51             =over
52              
53             =item C
54              
55             dampeningFactor => 0.85
56              
57             C is the dampening factor used when computing pagerank. It
58             must be a value ranging from zero to one; the default is 0.85. Note the
59             incidence matrix
60             generated from the graph is multiplied (scaled) by C, I
61             by C<1 - dampeningFactor>.
62              
63             =item C
64              
65             maxRelError => sqrt (machine-epsilon)
66              
67             C is the maximum I relative error that is permitted between
68             successive pagerank vectors before the iterative process to approximate the pagerank vector
69             should be stopped. The default is the square root of the systems machine epsilon.
70             Usually, most pagerank values computed will have C<-log10(maxRelError)> digits of accuracy.
71             C must be positive and less than or equal to 0.01.
72              
73             =item C
74              
75             minIterations => 0
76              
77             C is the minimum number of iterations that will be computed
78             before the pagerank iterations are stopped, even if C is achieved.
79             The default is zero.
80              
81             =item C
82              
83             maxIterations => int (2 * ((maxRelError / ln (dampeningFactor) + 1))
84              
85             C is the maximum number of iterations that can be performed
86             to approximate the pagerank vector even if C is not achieved.
87             The default is C<2 * ((maxRelError / ln (dampeningFactor) + 1)>. If
88             C is zero, then C is one. If C
89             is one, then C is equal to the total nodes in the graph.
90              
91             =item C
92              
93             linkSinkNodes => 1
94              
95             In a directed graph sink nodes are the nodes with no edges emanating out
96             from them. In the pagerank algorithm these nodes are automatically linked
97             to all other nodes in the graph. To prevent this set C to zero;
98             the default is one.
99              
100             =item C
101              
102             directed => 1
103              
104             If C is true, the pagerank computations are done with the graph
105             edges being directed. If C is false, the pageranks are computed
106             treating the graph as undirected; the default value of C is one.
107              
108             =item C
109              
110             useEdgeWeights => 0
111              
112             If C is true, then any weight associated with an edge is
113             used in the computation of pagerank. The default weight for any edge without an
114             assigned weight is one. The default value of C is zero,
115             which forces all edge weights to be one.
116              
117             =back
118              
119             =cut
120              
121             sub new
122             {
123 23     23 1 108953 my ($Class, %Parameters) = @_;
124 23   33     556 my $Self = bless ({}, ref ($Class) || $Class);
125              
126             # set the default parameters.
127 23         132 my %parameters = $Self->_setDefaultParameters (%Parameters);
128 23         95 $Self->{defaultParameters} = \%parameters;
129              
130 23         117 return $Self;
131             }
132              
133             sub _setDefaultParameters
134             {
135 23     23   72 my ($Self, %Parameters) = @_;
136              
137             # set dampening factor, default is .85;
138 23 50       121 $Parameters{dampeningFactor} = 0.85 unless (exists ($Parameters{dampeningFactor}));
139 23 50       137 $Parameters{dampeningFactor} = abs ($Parameters{dampeningFactor}) if (exists ($Parameters{dampeningFactor}));
140 23 50       107 $Parameters{dampeningFactor} = 1 if ($Parameters{dampeningFactor} > 1);
141              
142             # set max relative error, default is sqrt (machine epsilon).
143 23 50       155 $Parameters{maxRelError} = sqrt ($Self->_getMachineEpsilon ()) unless (exists ($Parameters{maxRelError}));
144 23 50       118 $Parameters{maxRelError} = abs ($Parameters{maxRelError}) if (exists ($Parameters{maxRelError}));
145 23 50       69 $Parameters{maxRelError} = 0.01 if ($Parameters{maxRelError} > 0.01);
146              
147             # set default min iterations.
148 23 50       89 $Parameters{minIterations} = 1 unless (exists ($Parameters{minIterations}));
149 23         48 $Parameters{minIterations} = abs ($Parameters{minIterations});
150              
151             # set default max iterations.
152 23 50       67 unless (exists ($Parameters{maxIterations}))
153             {
154 23         39 $Parameters{maxIterations} = 1;
155 23 50       89 $Parameters{maxIterations} = 1 if ($Parameters{dampeningFactor} <= 0);
156 23 50       67 $Parameters{maxIterationsIsTotalNodes} = 1 if ($Parameters{dampeningFactor} >= 1);
157 23 50       54 if ($Parameters{dampeningFactor} < 1)
158             {
159 23         3449 $Parameters{maxIterations} = 2 * (int (log ($Parameters{maxRelError}) / log ($Parameters{dampeningFactor})) + 1);
160             }
161             }
162 23         78 $Parameters{maxIterations} = abs ($Parameters{maxIterations});
163 23 50       70 $Parameters{maxIterations} = 1 if ($Parameters{maxIterations} < 1);
164 23 50       152 $Parameters{maxIterations} = $Parameters{minIterations} if ($Parameters{maxIterations} < $Parameters{minIterations});
165              
166             # set type of graph, default is directed.
167 23 50       86 unless (exists ($Parameters{directed}))
168             {
169 23 50       65 if (exists ($Parameters{undirected})) { $Parameters{directed} = !$Parameters{undirected}; }
  0         0  
170 23         63 else { $Parameters{directed} = 1; }
171             }
172              
173             # set use of edge weights in graph, default is 0.
174 23 50       79 $Parameters{useEdgeWeights} = 0 unless (exists ($Parameters{useEdgeWeights}));
175              
176             # set linking of sinks nodes in graph, default is 1. if graph is
177             # undirected there are no sink nodes.
178 23 50       75 $Parameters{linkSinkNodes} = 1 unless (exists ($Parameters{linkSinkNodes}));
179              
180             # when forcing dangling nodes to link to all other nodes, this should be
181             # with a probability of (1 - dampenFactor) / totalNodes to keep the matrix
182             # stocastic; however, some implementation of Pagerank do not do this. the
183             # default is 1.
184 23 50       82 $Parameters{scaleDampeningFactor} = 1 unless (exists ($Parameters{scaleDampeningFactor}));
185              
186 23         247 return %Parameters;
187             }
188              
189             # gets all the parameters needed to compute the pagerank. uses the
190             # values set when the object was insantiated to set any missing values.
191             sub _getAllParameters
192             {
193 31     31   68 my ($Self, %Parameters) = @_;
194              
195             # set dampening factor.
196 31 100       135 $Parameters{dampeningFactor} = $Self->{defaultParameters}{dampeningFactor} unless (exists ($Parameters{dampeningFactor}));
197 31 50       223 $Parameters{dampeningFactor} = abs ($Parameters{dampeningFactor}) if (exists ($Parameters{dampeningFactor}));
198 31 50       95 $Parameters{dampeningFactor} = 1 if ($Parameters{dampeningFactor} > 1);
199              
200             # set max relative error.
201 31 50       127 $Parameters{maxRelError} = $Self->{defaultParameters}{maxRelError} unless (exists ($Parameters{maxRelError}));
202 31 50       705 $Parameters{maxRelError} = abs ($Parameters{maxRelError}) if (exists ($Parameters{maxRelError}));
203 31 50       80 $Parameters{maxRelError} = 0.01 if ($Parameters{maxRelError} > 0.01);
204              
205             # set default min iterations.
206 31 50       268 $Parameters{minIterations} = $Self->{defaultParameters}{minIterations} unless (exists ($Parameters{minIterations}));
207 31         69 $Parameters{minIterations} = abs ($Parameters{minIterations});
208              
209             # set default max iterations.
210 31 50       76 unless (exists ($Parameters{maxIterations}))
211             {
212 31         244 $Parameters{maxIterations} = $Self->{defaultParameters}{maxIterations};
213 31 100 66     361 if ((0 < $Parameters{dampeningFactor}) && ($Parameters{dampeningFactor} < 1))
214             {
215 30         138 $Parameters{maxIterations} = 2 * (int (log ($Parameters{maxRelError}) / log ($Parameters{dampeningFactor})) + 1);
216             }
217             }
218 31         58 $Parameters{maxIterations} = abs ($Parameters{maxIterations});
219 31 50       73 $Parameters{maxIterations} = 1 if ($Parameters{maxIterations} < 1);
220 31 50       278 $Parameters{maxIterations} = $Parameters{minIterations} if ($Parameters{maxIterations} < $Parameters{minIterations});
221              
222             # set the type of graph.
223 31         40 my $directed;
224 31 50       76 $directed = !$Parameters{undirected} if (exists ($Parameters{undirected}));
225 31 100       87 $directed = $Parameters{directed} if (exists ($Parameters{directed}));
226 31 50 66     303 $directed = $Parameters{graph}->is_directed () if (!defined ($directed) && exists ($Parameters{graph}));
227 31 100       91 $directed = $Self->{defaultParameters}{directed} unless defined $directed;
228 31         54 $Parameters{directed} = $directed;
229              
230             # set use of edge weights in graph, default is 0.
231 31 50       101 $Parameters{useEdgeWeights} = $Self->{defaultParameters}{useEdgeWeights} unless (exists ($Parameters{useEdgeWeights}));
232              
233             # set linking of sinks nodes in graph, default is 1. if graph is
234             # undirected there are no sink nodes.
235 31 50       127 $Parameters{linkSinkNodes} = $Self->{defaultParameters}{linkSinkNodes} unless (exists ($Parameters{linkSinkNodes}));
236              
237             # when forcing dangling nodes to link to all other nodes, this should be
238             # with a probability of (1 - dampenFactor) / totalNodes to keep the matrix
239             # stocastic; however, some implementation of Pagerank do not do this. the
240             # default is 1.
241 31 50       270 $Parameters{scaleDampeningFactor} = $Self->{defaultParameters}{scaleDampeningFactor} unless (exists ($Parameters{scaleDampeningFactor}));
242              
243 31         322 return %Parameters;
244             }
245              
246             =head1 METHOD
247              
248             =head2 C
249              
250             The method C computes the pagerank of each node in the graph.
251             The graph can be defined using the C parameter or by supplying a list of edges.
252             All the parameters used by the constructor C can also be set here and they will override
253             the values used with C. C returns a reference to a hash where the
254             keys are the graph nodes and the values are the pageranks of the node.
255              
256             =over
257              
258             =item C
259              
260             graph => Graph
261              
262             C must be a L object. If the C parameter was not set
263             with the constructor C or with this method, then C
264             is set to the value of L->L().
265              
266             =item C
267              
268             listOfEdges => [['a',10],[10,11]]
269              
270             C must be a list of edges, where an edge is
271             a pair of strings of the form C<[from-node, to-node]> or a triple of the
272             form C<[from-node, to-node, numeric-edge-weight]>. Note that C and C can
273             both be defined, in which case the union of their list of edges is used to compute the
274             pageranks of the nodes.
275              
276             =item C
277              
278             listOfNodes => ['a',10, 'b']
279              
280             C is optional but, must be the list of nodes in the graph when provided;
281             it defaults to all the nodes comprising the edges in C or C.
282              
283             =item C
284              
285             nodeWeights => {}
286              
287             C is an optional hash reference that can provide a weight for the
288             nodes. If C is not defined for any node in the graph, then each
289             node has a weight of C<1/scale(@listOfNodes)>. If C is defined for
290             at least one node in the graph, then the default weight of any undefined
291             node is zero.
292              
293             =back
294              
295             =cut
296              
297             sub getPagerankOfNodes
298             {
299 31     31 1 31442 my ($Self, %Parameters) = @_;
300              
301             # set any missing parameters to their default values.
302 31         129 %Parameters = $Self->_getAllParameters (%Parameters);
303              
304             # get the list of edges from the graph.
305 31         276 my @listOfEdges;
306             my @listOfNodes;
307 31 50       92 if (exists ($Parameters{graph}))
308             {
309             # get the graph.
310 0         0 my $graph = $Parameters{graph};
311              
312             # get the list of graph edges.
313 0         0 @listOfEdges = $graph->edges();
314              
315             # get the list of vertices.
316 0         0 @listOfNodes = $graph->vertices();
317              
318             # get the graph edge weights if they are to be used and exist.
319 0 0       0 if ($Parameters{useEdgeWeights})
320             {
321 0         0 foreach my $edge (@listOfEdges)
322             {
323 0         0 my $weight = $graph->get_edge_weight (@$edge);
324 0 0       0 $edge->[2] = $weight if (defined ($weight));
325             }
326             }
327             }
328              
329             # add edges from the parameter listOfEdges; assuming they are unique.
330 31 100       82 push @listOfEdges, @{$Parameters{listOfEdges}} if exists $Parameters{listOfEdges};
  21         1744  
331 31 100       92 push @listOfNodes, @{$Parameters{listOfNodes}} if exists $Parameters{listOfNodes};
  10         552  
332              
333 31         188 return $Self->_getPageranksOfNodesFromEdgeList
334             (
335             %Parameters,
336             listOfEdges => \@listOfEdges,
337             listOfNodes => \@listOfNodes
338             );
339             }
340              
341             sub _getPageranksOfNodesFromEdgeList
342             {
343 31     31   169 my ($Self, %Parameters) = @_;
344              
345             # get the list of edges which may have weights, default weight is 1.
346 31         238 my $listOfEdges = $Parameters{listOfEdges};
347              
348             # get the list of edges which may have weights, default weight is 1.
349 31         38 my $listOfNodes;
350 31 50       89 $listOfNodes = $Parameters{listOfNodes} if exists $Parameters{listOfNodes};
351              
352             # store the type of graph.
353 31         52 my $directed = $Parameters{directed};
354              
355             # used to build the row oriented matrix from the list of graph edges.
356 31         208 my %matrixRows;
357             my %columnSum;
358             my $addEdgeSub = sub
359             {
360 16517     16517   19681 my ($from, $to, $weight) = @_;
361              
362             # add the edge weight to its row.
363 16517 100       31949 unless (exists ($matrixRows{$to}))
364             {
365 11008         29083 $matrixRows{$to} = {};
366 11008         32310 $matrixRows{$to}->{$from} = $weight;
367             }
368             else
369             {
370 5509         10484 $matrixRows{$to}->{$from} += $weight;
371             }
372              
373             # accumulate the column sums, which are used to normalize them later.
374 16517 100       27746 unless (exists ($columnSum{$from}))
375             {
376 21         111 $columnSum{$from} = $weight;
377             }
378             else
379             {
380 16496         20871 $columnSum{$from} += $weight;
381             }
382              
383             # set the column sum of the $to node if not already set, this is used
384             # to keep track of sink nodes.
385 16517 100       58410 unless (exists ($columnSum{$to}))
386             {
387 10987         18529 $columnSum{$to} = 0;
388             }
389 31         591 };
390              
391             # convert the list of edges into a row oriented matrix.
392 31         245 foreach my $edge (@$listOfEdges)
393             {
394             # get the edge weight, it must be positive.
395 11017         11293 my $weight = 1;
396 11017 50       21170 $weight = abs $edge->[2] if (defined ($edge->[2]));
397 11017 50       18788 next if ($weight == 0);
398              
399             # add the edge to the matrix of rows.
400 11017         22475 &$addEdgeSub ($edge->[0], $edge->[1], $weight);
401 11017 100       27363 &$addEdgeSub ($edge->[1], $edge->[0], $weight) unless ($directed);
402             }
403              
404             # if $listOfNodes is defined, ensure any missing nodes are added.
405 31 50       115 if (defined $listOfNodes)
406             {
407 31         65 foreach my $node (@$listOfNodes)
408             {
409 4744 50       9379 unless (exists ($columnSum{$node}))
410             {
411 4744         7941 $columnSum{$node} = 0;
412             }
413             }
414             }
415              
416             # normalize the column sums of the matrix and find all node sinks.
417 31         53 my @sinkNodes;
418 31         3294 my @rowNodes = keys %matrixRows;
419 31         589 while (my ($node, $sum) = each %columnSum)
420             {
421 15752 100       25608 if ($sum == 0)
422             {
423             # if the column sum for a node is zero, it is a sink.
424 4744         10675 push @sinkNodes, $node;
425             }
426             else
427             {
428             # normalize the columns of the node so it sums to 1.
429 11008         17337 foreach my $rowNode (@rowNodes)
430             {
431 7700064 100       16246613 if (exists ($matrixRows{$rowNode}->{$node}))
432             {
433 16517         45709 $matrixRows{$rowNode}->{$node} /= $sum;
434             }
435             }
436             }
437             }
438              
439             # get the list of all the nodes.
440 31         4304 my @allNodes = keys %columnSum;
441              
442             # get the total number of nodes.
443 31         735 my $totalNodes = @allNodes;
444              
445             # get or make the nodeWeights vector.
446 31         37 my %nodeWeights;
447 31 50       116 %nodeWeights = %{$Parameters{nodeWeights}} if exists $Parameters{nodeWeights};
  0         0  
448              
449             # ensure $nodeWeights is nonegative for all nodes.
450 31         70 my $sum = 0;
451 31         82 foreach my $node (@allNodes)
452             {
453             # if a value is not defined for a node, make it zero at first.
454 15752 50       31746 $nodeWeights{$node} = 0 unless exists $nodeWeights{$node};
455              
456             # force values to be nonnegative.
457 15752 50       24644 $nodeWeights{$node} = -$nodeWeights{$node} if ($nodeWeights{$node} < 0);
458              
459             # sum the positive values.
460 15752         17666 $sum += $nodeWeights{$node};
461             }
462              
463             # ensure $nodeWeights sum to one.
464 31 50       111 if ($sum > 0)
465             {
466 0         0 foreach my $node (@allNodes) { $nodeWeights{$node} /= $sum; }
  0         0  
467             }
468             else
469             {
470 31         68 foreach my $node (@allNodes) { $nodeWeights{$node} = 1 / $totalNodes; }
  15752         19444  
471             }
472              
473              
474             # initialize the pagerank vector;
475 31         78 my $pagerank = {};
476 31 50       140 return $pagerank if ($totalNodes == 0);
477 31         80 foreach my $node (@allNodes) { $pagerank->{$node} = $nodeWeights{$node}; }
  15752         26351  
478 31         74 my $newPageRank = {};
479              
480             # set the maximum number of iterations.
481 31         73 my $maxIterations = $Parameters{maxIterations};
482 31 50       133 $maxIterations = $totalNodes if exists $Parameters{maxIterationsIsTotalNodes};
483              
484 31         113 for (my $iteration = 0; $iteration < $maxIterations; $iteration++)
485             {
486             # first set the new page rank to the average pageranks times (1 - $dampeningFactor).
487 162 50       374 if ($Parameters{scaleDampeningFactor})
488             {
489             #my $sum = 0;
490             #foreach my $node (@allNodes) { $sum += $pagerank->{$node}; }
491             #$sum *= (1 - $Parameters{dampeningFactor}) / $totalNodes;
492 162         241 foreach my $node (@allNodes) { $newPageRank->{$node} = (1 - $Parameters{dampeningFactor}) * $nodeWeights{$node}; }
  32304         54876  
493             }
494             else
495             {
496 0         0 foreach my $node (@allNodes) { $newPageRank->{$node} = 1 - $Parameters{dampeningFactor}; }
  0         0  
497             }
498              
499             # add in the values for the sink nodes.
500 162 50       475 if ($Parameters{linkSinkNodes})
501             {
502 162         180 my $sinkSum = 0;
503 162         280 foreach my $sinkNode (@sinkNodes)
504             {
505 9488         10801 $sinkSum += $pagerank->{$sinkNode};
506             }
507 162         269 $sinkSum *= $Parameters{dampeningFactor} / $totalNodes;
508 162         238 foreach my $node (@allNodes) { $newPageRank->{$node} += $sinkSum; }
  32304         37377  
509             }
510              
511             # add in the rank from the graph links.
512 162         285 foreach my $rowNode (@rowNodes)
513             {
514 22816         25414 my $sum = 0;
515 22816         20984 while (my ($colNode, $value) = each %{$matrixRows{$rowNode}})
  57550         159054  
516             {
517 34734         64641 $sum += $value * $pagerank->{$colNode};
518             }
519 22816         43336 $newPageRank->{$rowNode} += $Parameters{dampeningFactor} * $sum;
520             }
521              
522             # normalize (for rounding error stability -- i hope) then swap pagerank vectors.
523 162         510 _normalizeByNorm1 ($newPageRank, \@allNodes);
524 162         325 ($pagerank, $newPageRank) = ($newPageRank, $pagerank);
525              
526             # compute the error.
527 162         200 my $error = 0;
528 162         183 my $totalNonzero = 0;
529 162         237 foreach my $node (@allNodes)
530             {
531 32304 50       49398 if ($pagerank->{$node} != 0)
532             {
533 32304         61349 $error += abs (($newPageRank->{$node} - $pagerank->{$node}) / $pagerank->{$node});
534             }
535             else
536             {
537 0         0 $error += abs ($newPageRank->{$node} - $pagerank->{$node});
538             }
539             }
540 162         281 $error /= $totalNodes;
541             #print $iteration . ' ' . $error . "\n";
542              
543             # stop iterating if the error is small enough, unless the minIterations has
544             # not been reached.
545 162 100 100     955 last if (($error < $Parameters{maxRelError}) && ($iteration >= $Parameters{minIterations}));
546             }
547              
548             # normalize the pagerank vector (for rounding error stability -- i hope).
549 31         117 _normalizeByNorm1 ($pagerank, \@allNodes);
550              
551 31         16505 return $pagerank;
552             }
553              
554             # normalize $hashVector so it sums to one (or zero).
555             sub _normalizeByNorm1
556             {
557 193     193   300 my ($hashVector, $indices) = @_;
558 193         208 my $sum = 0;
559 193         312 foreach my $node (@$indices) { $sum += $hashVector->{$node}; }
  48056         61020  
560 193 50       529 $sum = 1 if ($sum == 0);
561 193         300 foreach my $node (@$indices) { $hashVector->{$node} /= $sum; }
  48056         61169  
562 193         424 return 1;
563             }
564              
565             # get the value of machine epsilon, sort of, really
566             # the unit roundoff value.
567             sub _getMachineEpsilon
568             {
569 23     23   44 my $one = 1;
570 23         34 my $epsilon = 2;
571 23         41 my $halfOfepsilon = 1;
572 23         43 my $powerOf2 = 0;
573 23         136 my $sum;
574             do
575 23   66     39 {
576 1219         1260 $epsilon = $halfOfepsilon;
577 1219         1068 $halfOfepsilon = $epsilon / 2;
578 1219         1068 $sum = 1 + $halfOfepsilon;
579 1219         3946 ++$powerOf2;
580             }
581             until (($sum == $one) || ($powerOf2 > 2048)) ;
582 23         109 return $epsilon;
583             }
584              
585             =head1 EXAMPLES
586              
587             A rather dull example with one node and no edges:
588              
589             use Graph;
590             use Graph::Centrality::Pagerank;
591             use Data::Dump qw(dump);
592             my $ranker = Graph::Centrality::Pagerank->new();
593             my $listOfNodes = [1];
594             dump $ranker->getPagerankOfNodes (listOfNodes => $listOfNodes);
595             # dumps:
596             # {
597             # 1 => 1
598             # }
599              
600             An example of a graph with two components:
601              
602             use Graph::Centrality::Pagerank;
603             use Data::Dump qw(dump);
604             my $ranker = Graph::Centrality::Pagerank->new();
605             my $listOfEdges = [[1,2],[3,4]];
606             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges);
607             # dumps:
608             # {
609             # 1 => "0.175438596989046",
610             # 2 => "0.324561403010954",
611             # 3 => "0.175438596989046",
612             # 4 => "0.324561403010954",
613             # }
614              
615             In this case the edges are placed in a L:
616              
617             use Graph;
618             use Graph::Centrality::Pagerank;
619             use Data::Dump qw(dump);
620             my $listOfEdges = [[1,2],[3,4]];
621             my $graph = Graph->new (edges => $listOfEdges);
622             my $ranker = Graph::Centrality::Pagerank->new();
623             dump $ranker->getPagerankOfNodes (graph => $graph);
624             # dumps:
625             # {
626             # 1 => "0.175438596989046",
627             # 2 => "0.324561403010954",
628             # 3 => "0.175438596989046",
629             # 4 => "0.324561403010954",
630             # }
631              
632             Below is the first example in the paper
633             I by David Austin.
634              
635             use Graph::Centrality::Pagerank;
636             use Data::Dump qw(dump);
637             my $ranker = Graph::Centrality::Pagerank->new();
638             my $listOfEdges = [[1,2],[1,3],[2,4],[3,2],[3,5],[4,2],[4,5],[4,6],[5,6],
639             [5,7],[5,8],[6,8],[7,5],[7,1],[7,8],[8,6],[8,7]];
640             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges,
641             dampeningFactor => 1);
642             # dumps:
643             # {
644             # 1 => "0.0599999994835539",
645             # 2 => "0.0675000002254998",
646             # 3 => "0.0300000002967361",
647             # 4 => "0.0674999997408677",
648             # 5 => "0.0974999994123176",
649             # 6 => "0.202500001447512",
650             # 7 => "0.180000001348251",
651             # 8 => "0.294999998045262",
652             # }
653              
654             Below is the second example in the paper. Notice C is
655             set to zero.
656              
657             use Graph::Centrality::Pagerank;
658             use Data::Dump qw(dump);
659             my $ranker = Graph::Centrality::Pagerank->new();
660             my $listOfEdges = [[1,2]];
661             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges,
662             dampeningFactor => 1, linkSinkNodes => 0);
663             # dumps:
664             # { 1 => 0, 2 => 0 }
665              
666             Below is the third example in the paper. Notice in this case
667             C is set to one, the default value.
668              
669             use Graph::Centrality::Pagerank;
670             use Data::Dump qw(dump);
671             my $ranker = Graph::Centrality::Pagerank->new();
672             my $listOfEdges = [[1,2]];
673             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges,
674             dampeningFactor => 1, linkSinkNodes => 1);
675             # dumps:
676             # { 1 => "0.33333333209157", 2 => "0.66666666790843" }
677              
678             Below is the fourth example in the paper. The
679             result is different from the paper since the starting vector for
680             L is
681              
682             { 1 => "0.2", 2 => "0.2", 3 => "0.2", 4 => "0.2", 5 => "0.2" }
683              
684             while the starting vector in the paper is
685              
686             { 1 => 1, 2 => 0, 3 => 0, 4 => 0, 5 => 0 }.
687              
688             use Graph::Centrality::Pagerank;
689             use Data::Dump qw(dump);
690             my $ranker = Graph::Centrality::Pagerank->new();
691             my $listOfEdges = [[1,2],[2,3],[3,4],[4,5],[5,1]];
692             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges,
693             dampeningFactor => 1, linkSinkNodes => 0);
694             # dumps:
695             # { 1 => "0.2", 2 => "0.2", 3 => "0.2", 4 => "0.2", 5 => "0.2" }
696              
697             Below is the fifth example in the paper.
698              
699             use Graph::Centrality::Pagerank;
700             use Data::Dump qw(dump);
701             my $ranker = Graph::Centrality::Pagerank->new();
702             my $listOfEdges = [[1,3],[1,2],[2,4],[3,2],[3,5],[4,2],[4,5],[4,6],[5,6],
703             [5,7],[5,8],[6,8],[7,5],[7,8],[8,6],[8,7]];
704             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges,
705             dampeningFactor => 1, linkSinkNodes => 0);
706             # dumps:
707             # {
708             # 1 => 0,
709             # 2 => "2.39601089109228e-54",
710             # 3 => 0,
711             # 4 => "5.47659632249665e-54",
712             # 5 => "0.119999999997811",
713             # 6 => "0.240000000003975",
714             # 7 => "0.240000000003975",
715             # 8 => "0.399999999994238",
716             # }
717              
718             An example of the effect of including edge weights:
719              
720             use Graph::Centrality::Pagerank;
721             use Data::Dump qw(dump);
722             my $ranker = Graph::Centrality::Pagerank->new();
723             my $listOfEdges = [[2,1],[2,3]];
724             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges);
725             $listOfEdges = [[2,1,2],[2,3,1]];
726             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges,
727             useEdgeWeights => 1);
728              
729             # dumps:
730             # all edges have weight 1.
731             # {
732             # 1 => "0.370129870353883",
733             # 2 => "0.259740259292235",
734             # 3 => "0.370129870353883",
735             # }
736             # edge [2, 1] has twice the weight of edge [2,3].
737             # {
738             # 1 => "0.406926407374432",
739             # 2 => "0.259740259292235",
740             # 3 => "0.333333333333333",
741             # }
742              
743             An example of the effect of including node weights:
744              
745             use Graph;
746             use Graph::Centrality::Pagerank;
747             use Data::Dump qw(dump);
748             my $ranker = Graph::Centrality::Pagerank->new();
749             my $listOfEdges = [[1,2],[2,3]];
750             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges);
751             dump $ranker->getPagerankOfNodes (listOfEdges => $listOfEdges,
752             nodeWeights => {2 => .9, 3 => .1 });
753              
754             # dumps:
755             # {
756             # 1 => "0.184416783248514",
757             # 2 => "0.341171047056969",
758             # 3 => "0.474412169694517",
759             # }
760             # {
761             # 1 => "0.135592438389592",
762             # 2 => "0.385846009631034",
763             # 3 => "0.478561551979374",
764             # }
765              
766             A example of the modules speed, or lack of.
767              
768             use Graph::Centrality::Pagerank;
769             use Data::Dump qw(dump);
770             my $ranker = Graph::Centrality::Pagerank->new();
771             my @listOfEdges;
772             for (my $i = 0; $i < 1000000; $i++)
773             { push @listOfEdges, [int rand 10000, int rand 10000]; }
774             my $startTime = time;
775             my $pageranks = $ranker->getPagerankOfNodes (listOfEdges => \@listOfEdges);
776             print time()-$startTime . "\n";
777             # prints:
778             # a non-negative integer after a long time.
779              
780             =head1 INSTALLATION
781              
782             To install the module run the following commands:
783              
784             perl Makefile.PL
785             make
786             make test
787             make install
788              
789             If you are on a windows box you should use 'nmake' rather than 'make'.
790              
791             =head1 BUGS
792              
793             Please email bugs reports or feature requests to C, or through
794             the web interface at L. The author
795             will be notified and you can be automatically notified of progress on the bug fix or feature request.
796              
797             =head1 AUTHOR
798              
799             Jeff Kubina
800              
801             =head1 COPYRIGHT
802              
803             Copyright (c) 2009 Jeff Kubina. All rights reserved.
804             This program is free software; you can redistribute
805             it and/or modify it under the same terms as Perl itself.
806              
807             The full text of the license can be found in the
808             LICENSE file included with this module.
809              
810             =head1 KEYWORDS
811              
812             centrality measure, eigenvector centrality, graph, network, pagerank
813              
814             =head1 SEE ALSO
815              
816             =begin html
817              
818            

A good tutorial on the pagerank algorithm is the article

819             How Google Finds Your Needle in the Web's Haystack by David Austin.

820              
821             =end html
822              
823             L
824              
825             =begin html
826              
827             centrality measure,
828             eigenvector centrality,
829             graph,
830             network,
831             pagerank
832              
833             =end html
834              
835             =cut
836              
837             1;
838             # The preceding line will help the module return a true value