|
import { defaults } from '../../util'; |
|
import { inPlaceSumNormalize } from '../../math'; |
|
|
|
const pageRankDefaults = defaults({ |
|
dampingFactor: 0.8, |
|
precision: 0.000001, |
|
iterations: 200, |
|
weight: edge => 1 |
|
}); |
|
|
|
let elesfn = ({ |
|
|
|
pageRank: function( options ){ |
|
let { dampingFactor, precision, iterations, weight } = pageRankDefaults(options); |
|
let cy = this._private.cy; |
|
let { nodes, edges } = this.byGroup(); |
|
let numNodes = nodes.length; |
|
let numNodesSqd = numNodes * numNodes; |
|
let numEdges = edges.length; |
|
|
|
|
|
|
|
|
|
let matrix = new Array(numNodesSqd); |
|
let columnSum = new Array(numNodes); |
|
let additionalProb = (1 - dampingFactor) / numNodes; |
|
|
|
|
|
for( let i = 0; i < numNodes; i++ ){ |
|
for( let j = 0; j < numNodes; j++ ){ |
|
let n = i * numNodes + j; |
|
|
|
matrix[n] = 0; |
|
} |
|
|
|
columnSum[i] = 0; |
|
} |
|
|
|
|
|
for( let i = 0; i < numEdges; i++ ){ |
|
let edge = edges[ i ]; |
|
let srcId = edge.data('source'); |
|
let tgtId = edge.data('target'); |
|
|
|
|
|
if( srcId === tgtId ){ continue; } |
|
|
|
let s = nodes.indexOfId( srcId ); |
|
let t = nodes.indexOfId( tgtId ); |
|
let w = weight( edge ); |
|
let n = t * numNodes + s; |
|
|
|
|
|
matrix[n] += w; |
|
|
|
|
|
columnSum[s] += w; |
|
} |
|
|
|
|
|
|
|
let p = 1.0 / numNodes + additionalProb; |
|
|
|
|
|
for( let j = 0; j < numNodes; j++ ){ |
|
if( columnSum[j] === 0 ){ |
|
|
|
for( let i = 0; i < numNodes; i++ ){ |
|
let n = i * numNodes + j; |
|
matrix[n] = p; |
|
} |
|
} else { |
|
|
|
for( let i = 0; i < numNodes; i++ ){ |
|
let n = i * numNodes + j; |
|
|
|
matrix[n] = matrix[n] / columnSum[j] + additionalProb; |
|
} |
|
} |
|
} |
|
|
|
|
|
let eigenvector = new Array(numNodes); |
|
let temp = new Array(numNodes); |
|
let previous; |
|
|
|
|
|
|
|
for( let i = 0; i < numNodes; i++ ){ |
|
eigenvector[i] = 1; |
|
} |
|
|
|
for( let iter = 0; iter < iterations; iter++ ){ |
|
|
|
for( let i = 0; i < numNodes; i++ ){ |
|
temp[i] = 0; |
|
} |
|
|
|
|
|
for( let i = 0; i < numNodes; i++ ){ |
|
for( let j = 0; j < numNodes; j++ ){ |
|
let n = i * numNodes + j; |
|
|
|
temp[i] += matrix[n] * eigenvector[j]; |
|
} |
|
} |
|
|
|
inPlaceSumNormalize( temp ); |
|
previous = eigenvector; |
|
eigenvector = temp; |
|
temp = previous; |
|
|
|
let diff = 0; |
|
|
|
for( let i = 0; i < numNodes; i++ ){ |
|
let delta = previous[i] - eigenvector[i]; |
|
|
|
diff += delta * delta; |
|
} |
|
|
|
|
|
if( diff < precision ){ |
|
break; |
|
} |
|
} |
|
|
|
|
|
let res = { |
|
rank: function( node ){ |
|
node = cy.collection(node)[0]; |
|
|
|
return eigenvector[ nodes.indexOf(node) ]; |
|
} |
|
}; |
|
|
|
|
|
return res; |
|
} |
|
|
|
}); |
|
|
|
export default elesfn; |
|
|