Completed
Push — master ( 195fbe...724c19 )
by Ventaquil
02:47
created

Dijkstra::getMinimalRelation()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
rs 8.8571
cc 5
eloc 12
nc 6
nop 3
1
<?php
2
3
namespace PHPAlgorithms;
4
5
use Closure;
6
use PHPAlgorithms\Dijkstra\Creator;
7
use PHPAlgorithms\Dijkstra\Exceptions\Exception;
8
use PHPAlgorithms\Dijkstra\Path;
9
use PHPAlgorithms\Dijkstra\Point;
10
11
class Dijkstra {
12
    private $points = array();
13
14
    public function __construct($function = null)
15
    {
16
        if (!is_null($function)) {
17
            $this->add($function);
18
        }
19
    }
20
21
    public function add($function)
22
    {
23
        if (!($function instanceof Closure)) {
24
            throw new Exception('Sent argument is not instance of Closure');
25
        }
26
27
        $creator = new Creator();
28
        $function($creator);
29
30
        if (empty($this->points)) {
31
            $this->points = $creator->dumpPoints();
32
        } else {
33
            $index = count($this->points);
34
35
            foreach ($creator->dumpPoints() as $point) {
36
                $this->points[$index] = $point;
37
                $point->id = $index;
38
39
                $index++;
40
            }
41
        }
42
43
        return $this;
44
    }
45
46
    public function generate($point)
47
    {
48
        if ($point instanceof Point) {
49
            $point = $point->id;
0 ignored issues
show
Bug introduced by
The property id does not seem to exist in PHPAlgorithms\Dijkstra\Point.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
50
        }
51
52
        if (!isset($this->points[$point])) {
53
            throw new Exception("Point with id {$point} not exists");
54
        }
55
56
        $visited = array();
57
        $unvisited = array_keys($this->points);
58
        $paths = array();
59
        $previous = null;
60
        $relation = null;
61
62
        do {
63
            unset($unvisited[$point]);
64
            $visited[$point] = $point;
65
66
            if (!isset($paths[$point])) {
67
                $paths[$point] = (new Path())->addNode($point);
68
            }
69
70
            if (!is_null($previous)) {
71
                if (!isset($paths[$point])) {
72
                    $paths[$point]->copy($paths[$previous]);
73
                    $paths[$point]->addNode($point, $relation->distance);
74
                }
75
            }
76
77
            $relation = $this->getMinimalRelation($unvisited, $paths, $point);
78
79
            $this->updatePaths($paths, $point);
80
81
            $previous = $point;
82
83
            if (!is_null($relation)) {
84
                $point = $relation->to
85
                                  ->id;
86
            } else {
87
                $point = null;
88
            }
89
        } while (!is_null($point));
90
91
        return $paths;
92
    }
93
94
    public function generateAll()
95
    {
96
        $generated = array();
97
98
        foreach ($this->points as $index => $point) {
99
            $generated[$index] = $this->generate($point);
100
        }
101
102
        return $generated;
103
    }
104
105
    private function getMinimalRelation($unvisited, $paths, $point)
106
    {
107
        $minimalValue = INF;
108
        $minimalIndex = -1;
109
110
        foreach ($this->points[$point]->relations as $index => $relation) {
111
            if (($minimalValue > ($relation->distance + $paths[$point]->distance)) && isset($unvisited[$relation->to->id])) {
112
                $minimalIndex = $index;
113
                $minimalValue = $relation->distance + $paths[$point]->distance;
114
            }
115
        }
116
117
        if ($minimalIndex != -1) {
118
            return $this->points[$point]
119
                        ->relations[$minimalIndex];
120
        } else {
121
            return null;
122
        }
123
    }
124
125
    public function updatePaths(&$paths, $point)
126
    {
127
        foreach ($this->points[$point]->relations as $relation) {
128
            if (isset($paths[$relation->to->id])) {
129
                if ($paths[$relation->to->id]->distance > ($paths[$point]->distance + $relation->distance)) {
130
                    $paths[$relation->to->id]->copy($paths[$point])
131
                                             ->addNode($relation->to->id, $relation->distance);
132
                }
133
            } else {
134
                $paths[$relation->to->id] = new Path();
135
                $paths[$relation->to->id]->copy($paths[$point])
0 ignored issues
show
Documentation introduced by
$paths[$point] is of type object<PHPAlgorithms\Dijkstra\Path>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
136
                                         ->addNode($relation->to->id, $relation->distance);
137
            }
138
        }
139
    }
140
}
141