/** * Calculate the PageRank for all nodes in $graph. * @param Graph $graph * @param bool $keepAllRoundData [optional]. Default: false. If true, the values for every round of calculation is kept. Great for understanding what's going on during the calculation. * @return PageRankResult */ public function calculatePagerank(Graph $graph, $keepAllRoundData = false) { $round = 0; $rounds = []; $ns = $graph->getNodes(); $edges = $graph->getEdges(); /** @var PageRankNode[] $nodes */ $nodes = []; //transform to PageRankNodes foreach ($edges as $edge) { $prFromNode = $this->getPageRankNode($edge->getFrom(), $nodes); $prNodeTo = $this->getPageRankNode($edge->getTo(), $nodes); $prFromNode->addLinkTo($prNodeTo); $prNodeTo->addLinkFrom($prFromNode); } //transform (remaining) disconnected Nodes (that are not part of an Edge) to PageRankNodes foreach ($ns as $node) { $this->getPageRankNode($node, $nodes); } $this->getLogger()->debug("Got " . count($nodes) . " nodes in total"); do { $distance = 0; $currentRound = new PageRankNodeHistory($round); $newPrCache = []; foreach ($nodes as $key => $node) { $node->setOldPr($node->getPr()); $newPr = $node->calculatePageRank($this->dampingFactor, count($nodes)); $curDistance = abs($node->getOldPr() - $newPr); if ($curDistance > $distance) { $distance = $curDistance; } $entry = new PageRankNodeHistoryEntry($node, $node->getOldPr(), $newPr); $newPrCache[$key] = $newPr; $currentRound->addEntry($entry); } foreach ($nodes as $key => $node) { $newPr = $newPrCache[$key]; $node->setPr($newPr); } if (!$keepAllRoundData) { $rounds = []; } $rounds[$round] = $currentRound; $round++; $this->getLogger()->debug("Calculating round {$round}. Max rounds: {$this->maxRounds}. Last max distance: {$distance}. Required max distance: {$this->maxDistance}"); } while ($round < $this->maxRounds && ($distance == 0 || $distance > $this->maxDistance)); $result = new PageRankResult($graph, $rounds); return $result; }