Completed
Push — master ( d31b6a...3535ea )
by Bingo
04:00
created

UndirectedSpecifics::removeVertex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace graphp\graph\specifics;
4
5
use graphp\graph\GraphInterface;
6
use graphp\edge\EdgeInterface;
7
use graphp\edge\EdgeSetFactoryInterface;
8
use graphp\edge\EdgeArraySetFactory;
9
use graphp\vertex\VertexInterface;
10
use graphp\vertex\VertexMap;
11
use graphp\vertex\VertexSet;
12
13
/**
14
 * Class UndirectedSpecifics
15
 *
16
 * @package graphp\graph\specifics
17
 */
18
class UndirectedSpecifics implements SpecificsInterface
19
{
20
    /**
21
     * The graph
22
     *
23
     * @var GraphInterface
24
     */
25
    protected $graph;
26
27
    /**
28
     * The vertex map
29
     *
30
     * @var VertexMap
31
     */
32
    protected $vertexMap;
33
34
    /**
35
     * The edge set factory
36
     *
37
     * @var EdgeSetFactoryInterface
38
     */
39
    protected $edgeSetFactory;
40
41
    /**
42
     * Construct a new undirected specifics
43
     *
44
     * @param GraphInterface $graph - the graph for which these specifics are for
45
     * @param EdgeSetFactoryInterface $edgeSetFactory - the edge set factory, used by the graph
46
     */
47
    public function __construct(GraphInterface $graph, ?EdgeSetFactoryInterface $edgeSetFactory = null)
48
    {
49
        $this->graph = $graph;
50
        $this->vertexMap = new VertexMap();
51
        $this->edgeSetFactory = $edgeSetFactory ?? new EdgeArraySetFactory();
52
    }
53
54
    /**
55
     * Add a vertex
56
     *
57
     * @param VertexInterface $vertex - vertex to be added
58
     */
59
    public function addVertex(VertexInterface $vertex): void
60
    {
61
        $this->vertexMap->put($vertex);
62
    }
63
64
    /**
65
     * Remove a vertex
66
     *
67
     * @param VertexInterface $vertex - vertex to be removed
68
     */
69
    public function removeVertex(VertexInterface $vertex): void
70
    {
71
        $this->vertexMap->remove($vertex);
72
    }
73
74
    /**
75
     * Get the vertex set
76
     *
77
     * @return VertexSet
78
     */
79
    public function getVertexSet(): VertexSet
80
    {
81
        return $this->vertexMap->keySet();
82
    }
83
84
    /**
85
     * Get all edges connecting the source vertex to the target vertex
86
     *
87
     * @param VertexInterface $sourceVertex - source vertex
88
     * @param VertexInterface $targetVertex - target vertex
89
     *
90
     * @return array
91
     */
92
    public function getAllEdges(VertexInterface $sourceVertex, VertexInterface $targetVertex): array
93
    {
94
        $edges = [];
95
        
96
        if (
97
            $this->graph->containsVertex($sourceVertex)
98
            && $this->graph->containsVertex($targetVertex)
99
        ) {
100
            $edges = $this->getEdgeContainer($sourceVertex)->getEdges();
101
            
102
            foreach ($edges as $edge) {
103
                $equals = $this->isEqualStraightOrInverted($sourceVertex, $targetVertex, $edge);
104
                
105
                if ($equals) {
106
                    $edges[] = $edge;
107
                }
108
            }
109
        }
110
        
111
        return $edges;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $edges could return the type graphp\edge\EdgeSet which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
112
    }
113
114
    /**
115
     * Get an edge connecting the source vertex to the target vertex
116
     *
117
     * @param VertexInterface $sourceVertex - source vertex
118
     * @param VertexInterface $targetVertex - target vertex
119
     *
120
     * @return null|EdgeInterface
121
     */
122
    public function getEdge(VertexInterface $sourceVertex, VertexInterface $targetVertex): ?EdgeInterface
123
    {
124
        if (
125
            $this->graph->containsVertex($sourceVertex)
126
            && $this->graph->containsVertex($targetVertex)
127
        ) {
128
            $edges = $this->getEdgeContainer($sourceVertex)->getEdges();
129
            
130
            foreach ($edges as $edge) {
131
                $equals = $this->isEqualStraightOrInverted($sourceVertex, $targetVertex, $edge);
132
                
133
                if ($equals) {
134
                    return $edge;
135
                }
136
            }
137
        }
138
        
139
        return null;
140
    }
141
142
    /**
143
     * Get all edges touching the specified vertex
144
     *
145
     * @param VertexInterface $vertex - the vertex for which a set of touching edges is to be returned
146
     *
147
     * @return array
148
     */
149
    public function edgesOf(VertexInterface $vertex): array
150
    {
151
        return $this->getEdgeContainer($vertex)->getEdges();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getEdgeCon...er($vertex)->getEdges() returns the type graphp\edge\EdgeSet which is incompatible with the type-hinted return array.
Loading history...
152
    }
153
154
    /**
155
     * Add the specified edge to the edge containers of its source and target vertices.
156
     *
157
     * @param EdgeInterface $edge - the edge to be added
158
     */
159
    public function addEdgeToTouchingVertices(EdgeInterface $edge): void
160
    {
161
        $sourceVertex = $this->graph->getEdgeSource($edge);
162
        $targetVertex = $this->graph->getEdgeTarget($edge);
163
        
164
        $this->getEdgeContainer($sourceVertex)->addEdge($edge);
165
        
166
        if (!$sourceVertex->equals($targetVertex)) {
167
            $this->getEdgeContainer($targetVertex)->addEdge($edge);
168
        }
169
    }
170
171
    /**
172
     * Remove the specified edge from the edge containers of its source and target vertices.
173
     *
174
     * @param EdgeInterface $edge - the edge to be removed
175
     */
176
    public function removeEdgeFromTouchingVertices(EdgeInterface $edge): void
177
    {
178
        $sourceVertex = $this->graph->getEdgeSource($edge);
179
        $targetVertex = $this->graph->getEdgeTarget($edge);
180
        
181
        $this->getEdgeContainer($sourceVertex)->removeEdge($edge);
182
        
183
        if (!$sourceVertex->equals($targetVertex)) {
184
            $this->getEdgeContainer($targetVertex)->removeEdge($edge);
185
        }
186
    }
187
188
    /**
189
     * Get all edges outgoing from the specified vertex
190
     *
191
     * @param VertexInterface $vertex - the vertex for which the list of outgoing edges to be returned
192
     *
193
     * @return array
194
     */
195
    public function outgoingEdgesOf(VertexInterface $vertex): array
196
    {
197
        return $this->getEdgeContainer($vertex)->getEdges();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getEdgeCon...er($vertex)->getEdges() returns the type graphp\edge\EdgeSet which is incompatible with the type-hinted return array.
Loading history...
198
    }
199
200
    /**
201
     * Get all edges incoming into the specified vertex
202
     *
203
     * @param VertexInterface $vertex - the vertex for which the list of incoming edges to be returned
204
     *
205
     * @return array
206
     */
207
    public function incomingEdgesOf(VertexInterface $vertex): array
208
    {
209
        return $this->getEdgeContainer($vertex)->getEdges();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getEdgeCon...er($vertex)->getEdges() returns the type graphp\edge\EdgeSet which is incompatible with the type-hinted return array.
Loading history...
210
    }
211
212
    /**
213
     * Get the degree of the specified vertex
214
     *
215
     * @param VertexInterface $vertex - the vertex whose degree is to be calculated
216
     *
217
     * @return int
218
     */
219
    public function degreeOf(VertexInterface $vertex): int
220
    {
221
        if ($this->graph->getType()->isAllowingSelfLoops()) {
0 ignored issues
show
Bug introduced by
The method getType() does not exist on graphp\graph\GraphInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to graphp\graph\GraphInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

221
        if ($this->graph->/** @scrutinizer ignore-call */ getType()->isAllowingSelfLoops()) {
Loading history...
222
            $degree = 0;
223
            $edges = $this->getEdgeContainer($vertex)->getEdges();
224
225
            foreach ($edges as $edge) {
226
                //if it is a loop, then count twice
227
                if ($graph->getEdgeSource($edge)->equals($this->graph->getEdgeTarget($edge))) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $graph seems to be never defined.
Loading history...
228
                    $degree += 2;
229
                } else {
230
                    $degree += 1;
231
                }
232
            }
233
234
            return $degree;
235
        } else {
236
            $this->getEdgeContainer($vertex)->edgeCount();
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return integer. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
237
        }
238
    }
239
240
    /**
241
     * Get the "in degree" of the specified vertex
242
     *
243
     * @param VertexInterface $vertex - the vertex whose in degree is to be calculated
244
     *
245
     * @return int
246
     */
247
    public function inDegreeOf(VertexInterface $vertex): int
248
    {
249
        return $this->degreeOf($vertex);
250
    }
251
252
    /**
253
     * Get the "out degree" of the specified vertex
254
     *
255
     * @param VertexInterface $vertex - the vertex whose out degree is to be calculated
256
     *
257
     * @return int
258
     */
259
    public function outDegreeOf(VertexInterface $vertex): int
260
    {
261
        return $this->degreeOf($vertex);
262
    }
263
264
    /**
265
     * Get the edge container for the specified vertex.
266
     *
267
     * @param VertexInterface $vertex - the vertex
268
     *
269
     * @return DirectedEdgeContainer
270
     */
271
    public function getEdgeContainer(VertexInterface $vertex): UndirectedEdgeContainer
272
    {
273
        $ec = $this->vertexMap->get($vertex);
274
        
275
        if (is_null($ec)) {
276
            $ec = new UndirectedEdgeContainer($this->edgeSetFactory, $vertex);
277
            $this->vertexMap->put($vertex, $ec);
278
        }
279
        
280
        return $ec;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $ec could return the type graphp\edge\EdgeContainerInterface which includes types incompatible with the type-hinted return graphp\graph\specifics\UndirectedEdgeContainer. Consider adding an additional type-check to rule them out.
Loading history...
281
    }
282
283
    /**
284
     * Check if both vertices are touching the edge
285
     *
286
     * @param VertexInterface $sourceVertex - source vertex
287
     * @param VertexInterface $targetVertex - target vertex
288
     * @param EdgeInterface $edge - the edge
289
     *
290
     * @return bool
291
     */
292
    private function isEqualStraightOrInverted(
293
        VertexInterface $sourceVertex,
294
        VertexInterface $targetVertex,
295
        EdgeInterface $edge
296
    ): bool {
297
        $straigt = $sourceVertex->equals($this->graph->getEdgeSource($edge))
298
                   && $targetVertex->equals($this->graph->getEdgeTarget($edge));
299
                   
300
        $inverted = $targetVertex->equals($this->graph->getEdgeSource($edge))
301
                   && $sourceVertex->equals($this->graph->getEdgeTarget($edge));
302
                   
303
        return $straigt || $inverted;
304
    }
305
}
306