Bellman-Ford shortest path algorithm PHP implementation

This commit is contained in:
Michal Zarnecki 2024-05-05 13:08:47 +02:00
parent 13972e0072
commit e502f58c80
2 changed files with 99 additions and 0 deletions

51
Graphs/BellmanFord.php Normal file
View File

@ -0,0 +1,51 @@
<?php
class Edge {
public $start;
public $end;
public int $weight;
}
/**
* The BellmanFord algorithm is an algorithm that computes shortest paths from a single source vertex to all of the
* other vertices in a weighted digraph.
* (https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm).
*
* @author Michał Żarnecki https://github.com/rzarno
* @param array $verticies An array of verticies names
* @param Edge[] $edges An array of edges
* @return string $start The starting vertex
*/
function bellmanFord(array $verticesNames, array $edges, string $start, bool $verbose = false)
{
$vertices = array_combine($verticesNames, array_fill(0, count($verticesNames), PHP_INT_MAX));
$change = true;
$round = 1;
while ($change) {
if ($verbose) {
echo "round $round\n";
}
$change = false;
foreach ($vertices as $vertice => $minWeight) {
if ($verbose) {
echo "checking vertice $vertice\n";
}
if ($start === $vertice) {
$vertices[$vertice] = 0;
}
foreach ($edges[$vertice] as $edge) {
if ($vertices[$edge->end] > $vertices[$vertice] + $edge->weight ) {
if ($verbose) {
echo "replace $vertice " . $vertices[$edge->end] . " with " . $vertices[$vertice] + $edge->weight . "\n ";
}
$vertices[$edge->end] = $vertices[$vertice] + $edge->weight;
$change = true;
}
}
}
$round++;
}
return $vertices;
}

View File

@ -0,0 +1,48 @@
<?php
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../../Graphs/BellmanFord.php';
use PHPUnit\Framework\TestCase;
class BellmanFordTest extends TestCase
{
public function testBellmanFord()
{
$edgesRaw = [
['S', 8, 'E'],
['E', 1, 'D'],
['D', -1, 'C'],
['S', 10, 'A'],
['D', -4, 'A'],
['A', 2, 'C'],
['C', -2, 'B'],
['B', 1, 'A'],
];
$vertices = [ 'S', 'A', 'B', 'C', 'D', 'E',];
#prepare array of edges listed by edge start to simplify Bellman-Ford updating weights of other edges
$edges = [];
foreach($edgesRaw as $edgeRaw) {
$edge = new Edge();
$edge->start = $edgeRaw[0];
$edge->end = $edgeRaw[2];
$edge->weight = $edgeRaw[1];
if (! isset($edges[$edgeRaw[0]])) {
$edges[$edgeRaw[0]] = [];
}
$edges[$edgeRaw[0]][] = $edge;
}
$result = bellmanFord($vertices, $edges, 'S');
$this->assertEquals($result, [
'S' => 0,
'A' => 5,
'B' => 5,
'C' => 7,
'D' => 9,
'E'=> 8
]);
}
}