Completed
Branch master (7ef6dd)
by Bingo
07:42 queued 03:47
created

DirectedSpecifics::outDegreeOf()   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 2
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\edge\EdgeSet;
10
use graphp\vertex\VertexInterface;
11
use graphp\vertex\VertexMap;
12
use graphp\vertex\VertexSet;
13
14
/**
15
 * Class DirectedSpecifics
16
 *
17
 * @package graphp\graph\specifics
18
 */
19
class DirectedSpecifics implements SpecificsInterface
20
{
21
    /**
22
     * The graph
23
     *
24
     * @var GraphInterface
25
     */
26
    protected $graph;
27
28
    /**
29
     * The vertex map
30
     *
31
     * @var VertexMap
32
     */
33
    protected $vertexMap;
34
35
    /**
36
     * The edge set factory
37
     *
38
     * @var EdgeSetFactoryInterface
39
     */
40
    protected $edgeSetFactory;
41
42
    /**
43
     * Construct a new directed specifics
44
     *
45
     * @param GraphInterface $graph - the graph for which these specifics are for
46
     * @param EdgeSetFactoryInterface $edgeSetFactory - the edge set factory, used by the graph
47
     */
48 12
    public function __construct(GraphInterface $graph, ?EdgeSetFactoryInterface $edgeSetFactory = null)
49
    {
50 12
        $this->graph = $graph;
51 12
        $this->vertexMap = new VertexMap();
52 12
        $this->edgeSetFactory = $edgeSetFactory ?? new EdgeArraySetFactory();
53 12
    }
54
55
    /**
56
     * Add a vertex
57
     *
58
     * @param VertexInterface $vertex - vertex to be added
59
     */
60 10
    public function addVertex(VertexInterface $vertex): void
61
    {
62 10
        $this->vertexMap->put($vertex);
63 10
    }
64
65
    /**
66
     * Remove a vertex
67
     *
68
     * @param VertexInterface $vertex - vertex to be removed
69
     */
70 1
    public function removeVertex(VertexInterface $vertex): void
71
    {
72 1
        $this->vertexMap->remove($vertex);
73 1
    }
74
75
    /**
76
     * Get the vertex set
77
     *
78
     * @return VertexSet
79
     */
80 10
    public function getVertexSet(): VertexSet
81
    {
82 10
        return $this->vertexMap->keySet();
83
    }
84
85
    /**
86
     * Get all edges connecting the source vertex to the target vertex
87
     *
88
     * @param VertexInterface $sourceVertex - source vertex
89
     * @param VertexInterface $targetVertex - target vertex
90
     *
91
     * @return EdgeSet
92
     */
93 4
    public function getAllEdges(VertexInterface $sourceVertex, VertexInterface $targetVertex): EdgeSet
94
    {
95 4
        $edges = new EdgeSet();
96
        
97
        if (
98 4
            $this->graph->containsVertex($sourceVertex)
99 4
            && $this->graph->containsVertex($targetVertex)
100
        ) {
101 4
            $allEdges = $this->getEdgeContainer($sourceVertex)->getOutgoing();
102
            
103 4
            foreach ($allEdges as $edge) {
104 4
                $equals = $this->graph->getEdgeTarget($edge)->equals($targetVertex);
105
                
106 4
                if ($equals && !$edges->contains($edge)) {
107 4
                    $edges[] = $edge;
108
                }
109
            }
110
        }
111
        
112 4
        return $edges;
113
    }
114
115
    /**
116
     * Get an edge connecting the source vertex to the target vertex
117
     *
118
     * @param VertexInterface $sourceVertex - source vertex
119
     * @param VertexInterface $targetVertex - target vertex
120
     *
121
     * @return null|EdgeInterface
122
     */
123 9
    public function getEdge(VertexInterface $sourceVertex, VertexInterface $targetVertex): ?EdgeInterface
124
    {
125
        if (
126 9
            $this->graph->containsVertex($sourceVertex)
127 9
            && $this->graph->containsVertex($targetVertex)
128
        ) {
129 9
            $edges = $this->getEdgeContainer($sourceVertex)->getOutgoing();
130
            
131 9
            foreach ($edges as $edge) {
132 4
                $equals = $this->graph->getEdgeTarget($edge)->equals($targetVertex);
133
                
134 4
                if ($equals) {
135 4
                    return $edge;
136
                }
137
            }
138
        }
139
        
140 9
        return null;
141
    }
142
143
    /**
144
     * Get all edges touching the specified vertex
145
     *
146
     * @param VertexInterface $vertex - the vertex for which a set of touching edges is to be returned
147
     *
148
     * @return EdgeSet
149
     */
150 4
    public function edgesOf(VertexInterface $vertex): EdgeSet
151
    {
152 4
        $edges = $this->getEdgeContainer($vertex)->getOutgoing()->getArrayCopy();
153 4
        $edges = new EdgeSet(array_merge($edges, $this->getEdgeContainer($vertex)->getIncoming()->getArrayCopy()));
154
        
155
        //remove only one copy of self-loop
156 4
        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

156
        if ($this->graph->/** @scrutinizer ignore-call */ getType()->isAllowingSelfLoops()) {
Loading history...
157 4
            $loops = array_unique($this->getAllEdges($vertex, $vertex)->getArrayCopy());
158
            
159 4
            foreach ($edges as $key => $edge) {
160 4
                if (($id = array_search($edge, $loops)) !== false) {
161
                    unset($edges[$key]);
162 4
                    unset($loops[$id]);
163
                }
164
            }
165
        }
166
        
167 4
        return $edges;
168
    }
169
170
    /**
171
     * Add the specified edge to the edge containers of its source and target vertices.
172
     *
173
     * @param EdgeInterface $edge - the edge to be added
174
     */
175 9
    public function addEdgeToTouchingVertices(EdgeInterface $edge): void
176
    {
177 9
        $sourceVertex = $this->graph->getEdgeSource($edge);
178 9
        $targetVertex = $this->graph->getEdgeTarget($edge);
179
        
180 9
        $this->getEdgeContainer($sourceVertex)->addOutgoingEdge($edge);
181 9
        $this->getEdgeContainer($targetVertex)->addIncomingEdge($edge);
182 9
    }
183
184
    /**
185
     * Remove the specified edge from the edge containers of its source and target vertices.
186
     *
187
     * @param EdgeInterface $edge - the edge to be removed
188
     */
189 1
    public function removeEdgeFromTouchingVertices(EdgeInterface $edge): void
190
    {
191 1
        $sourceVertex = $this->graph->getEdgeSource($edge);
192 1
        $targetVertex = $this->graph->getEdgeTarget($edge);
193
        
194 1
        $this->getEdgeContainer($sourceVertex)->removeOutgoingEdge($edge);
195 1
        $this->getEdgeContainer($targetVertex)->removeIncomingEdge($edge);
196 1
    }
197
198
    /**
199
     * Get all edges outgoing from the specified vertex
200
     *
201
     * @param VertexInterface $vertex - the vertex for which the list of outgoing edges to be returned
202
     *
203
     * @return EdgeSet
204
     */
205 3
    public function outgoingEdgesOf(VertexInterface $vertex): EdgeSet
206
    {
207 3
        return $this->getEdgeContainer($vertex)->getOutgoing();
208
    }
209
210
    /**
211
     * Get all edges incoming into the specified vertex
212
     *
213
     * @param VertexInterface $vertex - the vertex for which the list of incoming edges to be returned
214
     *
215
     * @return EdgeSet
216
     */
217 3
    public function incomingEdgesOf(VertexInterface $vertex): EdgeSet
218
    {
219 3
        return $this->getEdgeContainer($vertex)->getIncoming();
220
    }
221
222
    /**
223
     * Get the degree of the specified vertex
224
     *
225
     * @param VertexInterface $vertex - the vertex whose degree is to be calculated
226
     *
227
     * @return int
228
     */
229
    public function degreeOf(VertexInterface $vertex): int
230
    {
231
        return $this->inDegreeOf($vertex) + $this->outDegreeOf($vertex);
232
    }
233
234
    /**
235
     * Get the "in degree" of the specified vertex
236
     *
237
     * @param VertexInterface $vertex - the vertex whose in degree is to be calculated
238
     *
239
     * @return int
240
     */
241
    public function inDegreeOf(VertexInterface $vertex): int
242
    {
243
        return count($this->getEdgeContainer($vertex)->getIncoming());
244
    }
245
246
    /**
247
     * Get the "out degree" of the specified vertex
248
     *
249
     * @param VertexInterface $vertex - the vertex whose out degree is to be calculated
250
     *
251
     * @return int
252
     */
253
    public function outDegreeOf(VertexInterface $vertex): int
254
    {
255
        return count($this->getEdgeContainer($vertex)->getOutgoing());
256
    }
257
258
    /**
259
     * Get the edge container for the specified vertex.
260
     *
261
     * @param VertexInterface $vertex - the vertex
262
     *
263
     * @return DirectedEdgeContainer
264
     */
265 9
    public function getEdgeContainer(VertexInterface $vertex): DirectedEdgeContainer
266
    {
267 9
        $ec = $this->vertexMap->get($vertex);
268
        
269 9
        if (is_null($ec)) {
270 9
            $ec = new DirectedEdgeContainer($this->edgeSetFactory, $vertex);
271 9
            $this->vertexMap->put($vertex, $ec);
272
        }
273
        
274 9
        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\DirectedEdgeContainer. Consider adding an additional type-check to rule them out.
Loading history...
275
    }
276
}
277