diff --git a/algorithm/category.json b/algorithm/category.json
index 81c711fa..a18e3885 100644
--- a/algorithm/category.json
+++ b/algorithm/category.json
@@ -8,7 +8,8 @@
"bellman_ford": "Bellman-Ford",
"floyd_warshall": "Floyd-Warshall",
"topological_sort": "Topological-Sort",
- "bridges": "Find-Bridges"
+ "bridges": "Find-Bridges",
+ "page_rank": "PageRank Algorithm"
}
},
"cryptography": {
diff --git a/algorithm/graph_search/page_rank/basic/code.js b/algorithm/graph_search/page_rank/basic/code.js
new file mode 100644
index 00000000..608351b7
--- /dev/null
+++ b/algorithm/graph_search/page_rank/basic/code.js
@@ -0,0 +1,106 @@
+/*
+ PageRank Algorithm Version 1
+ Equation:
+ PR (X) = (1 - D) + D (Summation i->X (PR (I) / Out (i)))
+ NOTE: Algorithm uses the recommended damping factor (D). Number of iterations is small because only a small Web of 5 Pages is simulated
+*/
+
+function arraySum (array) {
+ return array.reduce (function (sum, curr) {
+ return sum + (curr ? 1 : 0); //if curr is 0 (no edge) or undefined (loop not allowed), sum remains unchanged
+ }, 0);
+}
+
+function showOutgoingEdges (i) {
+ G [i].forEach (function (edgeExists, j) {
+ edgeExists && graphTracer._visit (j, i)._wait () && graphTracer._leave (j, i)._wait ();
+ });
+}
+
+//PRECOMPUTATIONS
+
+logger._print ('Calculate Outgoing Edge Count for each Node');
+(function calculateOEC () {
+ var count = 0;
+ G.forEach (function (relations, i) {
+ outgoingEdgeCounts [i] = arraySum (relations);
+ showOutgoingEdges (i);
+
+ oecTracer._notify (i, outgoingEdgeCounts [i])._wait ();
+ oecTracer._denotify (i)._wait ();
+ });
+}) ();
+
+logger._print ('determine incoming nodes for each node');
+(function determineIN () {
+ for (var i = 0; i < G.length; i++) {
+ for (var j = 0; j < G.length; j++) {
+ if (G [i] [j]) {
+ //there's an edge FROM i TO j
+ graphTracer._visit (j, i)._wait ();
+
+ var nextPos = incomingNodes [j].indexOf (-1);
+ incomingNodes [j] [nextPos] = i;
+ inTracer._notify (j, nextPos, i)._wait ();
+ inTracer._denotify (j, nextPos)._wait ();
+
+ graphTracer._leave (j, i)._wait ();
+ }
+ }
+ }
+
+ //logger._print ('All -1s will be removed from incoming node records, they are irrelevant');
+ incomingNodes.forEach (function (arr) {
+ arr.splice (arr.indexOf (-1));
+ });
+}) ();
+
+function updateRank (nodeIndex) {
+ var inNodeSummation = 0, result;
+
+ logger._print ('Updating rank of ' + nodeIndex);
+ logger._print ('The incoming Nodes of ' + nodeIndex + ' are being highlighted');
+
+ incomingNodes [nodeIndex].forEach (function (incoming, i) {
+ inTracer._select (nodeIndex, i)._wait ();
+ logger._print ('Outgoing edge count of ' + incoming + ' is ' + outgoingEdgeCounts [incoming]);
+ oecTracer._select (incoming)._wait ();
+
+ inNodeSummation += (ranks [incoming] / outgoingEdgeCounts [incoming]);
+
+ oecTracer._deselect (incoming)._wait ();
+ inTracer._deselect (nodeIndex, i)._wait ();
+ });
+ logger._print ('In-Node summation of ' + nodeIndex + ' = ' + inNodeSummation);
+
+ result = (1 - damping) + (damping * inNodeSummation);
+ logger._print ('Therefore, using Equation, new rank of ' + nodeIndex + ' = ' + result);
+ return result;
+}
+
+var damping = 0.85,
+ iterations = 7;
+var initialRank = 1.0;
+
+logger._print ('Initialized all Page ranks to ' + initialRank);
+ranks = filledArray (G.length, initialRank);
+
+rankTracer._setData (ranks);
+logger._print ('Begin execution of PageRank Version #1');
+logger._print ('Equation used: PR (X) = (1 - D) + D (In-Node-Summation i->X (PR (I) / Out (i)))');
+logger._print ('D = Damping Factor, PR (X) = Page rank of Node X, i = the ith In-Node of X, Out (i) = outgoing Edge Count of i');
+logger._print ('');
+
+while (iterations--) {
+ for (var node = 0; node < ranks.length; node++) {
+ ranks [node] = updateRank (node);
+ rankTracer._notify (node, ranks [node])._wait ();
+ rankTracer._notify (node)._wait ();
+ }
+}
+
+logger._print ('Page Ranks have been converged to.')
+ranks.forEach (function (rank, node) {
+ logger._print ('Rank of Node #' + node + ' = ' + rank);
+});
+logger._print ('Done');
\ No newline at end of file
diff --git a/algorithm/graph_search/page_rank/basic/data.js b/algorithm/graph_search/page_rank/basic/data.js
new file mode 100644
index 00000000..97623181
--- /dev/null
+++ b/algorithm/graph_search/page_rank/basic/data.js
@@ -0,0 +1,21 @@
+function filledArray (length, value) {
+ return Array.apply (null, Array (length)).map (Number.prototype.valueOf, value);
+}
+
+var G = new DirectedGraph.random (5, 0.4),
+ ranks,
+ outgoingEdgeCounts = filledArray (G.length, 0),
+ incomingNodes;
+
+var graphTracer = new DirectedGraphTracer ('Web Page inter-connections'),
+ rankTracer = new Array1DTracer ('Web Page Ranks'),
+ oecTracer = new Array1DTracer ('Outgoing Edge Counts'),
+ inTracer = new Array2DTracer ('Incoming Nodes');
+
+var logger = new LogTracer ();
+
+graphTracer._setData (G);
+oecTracer._setData (outgoingEdgeCounts);
+
+for (incomingNodes = []; incomingNodes.length < G.length; incomingNodes.push (filledArray (G.length, -1)));
+inTracer._setData (incomingNodes);
\ No newline at end of file
diff --git a/algorithm/graph_search/page_rank/desc.json b/algorithm/graph_search/page_rank/desc.json
new file mode 100644
index 00000000..e9833312
--- /dev/null
+++ b/algorithm/graph_search/page_rank/desc.json
@@ -0,0 +1,17 @@
+{
+ "PageRank-Algorithm": "PageRank is an algorithm used by Google Search to rank websites in their search engine results.",
+ "Applications": [
+ "Web Page Indexing for refining search results"
+ ],
+ "Complexity": {
+ "time": "worst O(|V|+|E|)",
+ "space": "worst O(|V|)"
+ },
+ "References": [
+ "Princeton university",
+ "E-Factory"
+ ],
+ "files": {
+ "basic": "Version #1 of PageRank Algorithm (does not take into account the total number of nodes in the graph, i.e., number of pages on web)."
+ }
+}