Skip to content

Commit 82c3b61

Browse files
committed
Do not return zero weight for root vertex and support root loops
1 parent 7f6aef2 commit 82c3b61

File tree

3 files changed

+33
-12
lines changed

3 files changed

+33
-12
lines changed

src/ShortestPath/Base.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ protected function getEdgesToInternal(Vertex $endVertex, array $edges)
5252
{
5353
$currentVertex = $endVertex;
5454
$path = array();
55-
while ($currentVertex !== $this->vertex) {
55+
do {
5656
$pre = NULL;
5757
// check all edges to search for edge that points TO current vertex
5858
foreach ($edges as $edge) {
@@ -68,7 +68,7 @@ protected function getEdgesToInternal(Vertex $endVertex, array $edges)
6868
if ($pre === NULL) {
6969
throw new OutOfBoundsException('No edge leading to vertex');
7070
}
71-
}
71+
} while ($currentVertex !== $this->vertex);
7272

7373
return array_reverse($path);
7474
}
@@ -198,8 +198,6 @@ public function createGraph()
198198
protected function getEdgesCheapestPredecesor(array $predecessor)
199199
{
200200
$vertices = $this->vertex->getGraph()->getVertices();
201-
// start vertex doesn't have a predecessor
202-
unset($vertices[$this->vertex->getId()]);
203201

204202
$edges = array();
205203
foreach ($vertices as $vid => $vertex) {

src/ShortestPath/Dijkstra.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function getEdges()
1616
{
1717
$totalCostOfCheapestPathTo = Array();
1818
// start node distance
19-
$totalCostOfCheapestPathTo[$this->vertex->getId()] = 0;
19+
$totalCostOfCheapestPathTo[$this->vertex->getId()] = INF;
2020

2121
// just to get the cheapest vertex in the correct order
2222
$cheapestVertex = new SplPriorityQueue();
@@ -29,6 +29,8 @@ public function getEdges()
2929
// mark vertices when their cheapest path has been found
3030
$usedVertices = Array();
3131

32+
$isFirst = true;
33+
3234
// Repeat until all vertices have been marked
3335
$totalCountOfVertices = $this->vertex->getGraph()->getNumberOfVertices();
3436
for ($i = 0; $i < $totalCountOfVertices; ++$i) {
@@ -52,8 +54,12 @@ public function getEdges()
5254
break;
5355
}
5456

55-
// mark this vertex
56-
$usedVertices[$currentVertexId] = true;
57+
if ($isFirst) {
58+
$isFirst = false;
59+
} else {
60+
// mark this vertex
61+
$usedVertices[$currentVertexId] = true;
62+
}
5763

5864
// check for all edges of current vertex if there is a cheaper path (or IN OTHER WORDS: Add reachable nodes from currently added node and refresh the current possible distances)
5965
foreach ($currentVertex->getEdgesOut() as $edge) {
@@ -69,6 +75,9 @@ public function getEdges()
6975
if (!isset($usedVertices[$targetVertexId])) {
7076
// calculate new cost to vertex
7177
$newCostsToTargetVertex = $totalCostOfCheapestPathTo[$currentVertexId] + $weight;
78+
if (is_infinite($newCostsToTargetVertex)) {
79+
$newCostsToTargetVertex = $weight;
80+
}
7281

7382
if ((!isset($predecesVertexOfCheapestPathTo[$targetVertexId]))
7483
// is the new path cheaper?
@@ -88,6 +97,10 @@ public function getEdges()
8897
}
8998
}
9099

100+
if ($totalCostOfCheapestPathTo[$this->vertex->getId()] === INF) {
101+
unset($predecesVertexOfCheapestPathTo[$this->vertex->getId()]);
102+
}
103+
91104
// algorithm is done, return resulting edges
92105
return $this->getEdgesCheapestPredecesor($predecesVertexOfCheapestPathTo);
93106
}

src/ShortestPath/MooreBellmanFord.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ private function bigStep(array &$edges, array &$totalCostOfCheapestPathTo, array
3131
if (isset($totalCostOfCheapestPathTo[$fromVertex->getId()])) {
3232
// New possible costs of this path
3333
$newCost = $totalCostOfCheapestPathTo[$fromVertex->getId()] + $edge->getWeight();
34+
if (is_infinite($newCost)) {
35+
$newCost = $edge->getWeight();
36+
}
3437

3538
// No path has been found yet
3639
if (!isset($totalCostOfCheapestPathTo[$toVertex->getId()])
@@ -56,21 +59,28 @@ private function bigStep(array &$edges, array &$totalCostOfCheapestPathTo, array
5659
*/
5760
public function getEdges()
5861
{
59-
// start node distance
60-
$totalCostOfCheapestPathTo = array($this->vertex->getId() => 0);
62+
// start node distance, add placeholder weight
63+
$totalCostOfCheapestPathTo = array($this->vertex->getId() => INF);
6164

6265
// predecessor
6366
$predecessorVertexOfCheapestPathTo = array($this->vertex->getId() => $this->vertex);
6467

65-
// repeat (n-1) times
66-
$numSteps = $this->vertex->getGraph()->getNumberOfVertices() - 1;
68+
// the usal algorithm says we repeat (n-1) times.
69+
// but because we also want to check for loop edges on the start vertex,
70+
// we have to add an additional step:
71+
$numSteps = $this->vertex->getGraph()->getNumberOfVertices();
6772
$edges = $this->vertex->getGraph()->getEdges();
6873
$changed = true;
69-
// repeat n-1 times
74+
7075
for ($i = 0; $i < $numSteps && $changed; ++$i) {
7176
$changed = $this->bigStep($edges, $totalCostOfCheapestPathTo, $predecessorVertexOfCheapestPathTo);
7277
}
7378

79+
// no cheaper edge to start vertex found => remove placeholder weight
80+
if ($totalCostOfCheapestPathTo[$this->vertex->getId()] === INF) {
81+
unset($predecessorVertexOfCheapestPathTo[$this->vertex->getId()]);
82+
}
83+
7484
// algorithm is done, build graph
7585
$returnEdges = $this->getEdgesCheapestPredecesor($predecessorVertexOfCheapestPathTo);
7686

0 commit comments

Comments
 (0)