Completed
Branch master (66b2c3)
by Bingo
07:00 queued 02:56
created

DirectedSpecifics::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 3
c 1
b 0
f 1
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
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 14
    public function __construct(GraphInterface $graph, ?EdgeSetFactoryInterface $edgeSetFactory = null)
49
    {
50 14
        $this->graph = $graph;
51 14
        $this->vertexMap = new VertexMap();
52 14
        $this->edgeSetFactory = $edgeSetFactory ?? new EdgeArraySetFactory();
53 14
    }
54
55
    /**
56
     * Add a vertex
57
     *
58
     * @param VertexInterface $vertex - vertex to be added
59
     */
60 13
    public function addVertex(VertexInterface $vertex): void
61
    {
62 13
        $this->vertexMap->put($vertex);
63 13
    }
64
65
    /**
66
     * Remove a vertex
67
     *
68
     * @param VertexInterface $vertex - vertex to be removed
69
     */
70 3
    public function removeVertex(VertexInterface $vertex): void
71
    {
72 3
        $this->vertexMap->remove($vertex);
73 3
    }
74
75
    /**
76
     * Get the vertex set
77
     *
78
     * @return VertexSet
79
     */
80 13
    public function getVertexSet(): VertexSet
81
    {
82 13
        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 7
    public function getAllEdges(VertexInterface $sourceVertex, VertexInterface $targetVertex): EdgeSet
94
    {
95 7
        $edges = new EdgeSet();
96
        
97
        if (
98 7
            $this->graph->containsVertex($sourceVertex)
99 7
            && $this->graph->containsVertex($targetVertex)
100
        ) {
101 7
            $allEdges = $this->getEdgeContainer($sourceVertex)->getOutgoing();
102
            
103 7
            foreach ($allEdges as $edge) {
104 5
                $equals = $this->graph->getEdgeTarget($edge)->equals($targetVertex);
105
                
106 5
                if ($equals && !$edges->contains($edge)) {
107 5
                    $edges[] = $edge;
108
                }
109
            }
110
        }
111
        
112 7
        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 11
    public function getEdge(VertexInterface $sourceVertex, VertexInterface $targetVertex): ?EdgeInterface
124
    {
125
        if (
126 11
            $this->graph->containsVertex($sourceVertex)
127 11
            && $this->graph->containsVertex($targetVertex)
128
        ) {
129 11
            $edges = $this->getEdgeContainer($sourceVertex)->getOutgoing();
130
            
131 11
            foreach ($edges as $edge) {
132 5
                $equals = $this->graph->getEdgeTarget($edge)->equals($targetVertex);
133
                
134 5
                if ($equals) {
135 5
                    return $edge;
136
                }
137
            }
138
        }
139
        
140 11
        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 7
    public function edgesOf(VertexInterface $vertex): EdgeSet
151
    {
152 7
        $edges = $this->getEdgeContainer($vertex)->getOutgoing()->getArrayCopy();
153 7
        $edges = new EdgeSet(array_merge($edges, $this->getEdgeContainer($vertex)->getIncoming()->getArrayCopy()));
154
        
155
        //remove only one copy of self-loop
156 7
        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 7
            $loops = array_unique($this->getAllEdges($vertex, $vertex)->getArrayCopy());
158
            
159 7
            foreach ($edges as $key => $edge) {
160 6
                if (($id = array_search($edge, $loops)) !== false) {
161
                    unset($edges[$key]);
162 6
                    unset($loops[$id]);
163
                }
164
            }
165
        }
166
        
167 7
        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 11
    public function addEdgeToTouchingVertices(EdgeInterface $edge): void
176
    {
177 11
        $sourceVertex = $this->graph->getEdgeSource($edge);
178 11
        $targetVertex = $this->graph->getEdgeTarget($edge);
179
        
180 11
        $this->getEdgeContainer($sourceVertex)->addOutgoingEdge($edge);
181 11
        $this->getEdgeContainer($targetVertex)->addIncomingEdge($edge);
182 11
    }
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 2
    public function removeEdgeFromTouchingVertices(EdgeInterface $edge): void
190
    {
191 2
        $sourceVertex = $this->graph->getEdgeSource($edge);
192 2
        $targetVertex = $this->graph->getEdgeTarget($edge);
193
        
194 2
        $this->getEdgeContainer($sourceVertex)->removeOutgoingEdge($edge);
195 2
        $this->getEdgeContainer($targetVertex)->removeIncomingEdge($edge);
196 2
    }
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 4
    public function outgoingEdgesOf(VertexInterface $vertex): EdgeSet
206
    {
207 4
        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 4
    public function incomingEdgesOf(VertexInterface $vertex): EdgeSet
218
    {
219 4
        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 1
    public function degreeOf(VertexInterface $vertex): int
230
    {
231 1
        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 1
    public function inDegreeOf(VertexInterface $vertex): int
242
    {
243 1
        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 1
    public function outDegreeOf(VertexInterface $vertex): int
254
    {
255 1
        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 12
    public function getEdgeContainer(VertexInterface $vertex): DirectedEdgeContainer
266
    {
267 12
        $ec = $this->vertexMap->get($vertex);
268
        
269 12
        if (is_null($ec)) {
270 12
            $ec = new DirectedEdgeContainer($this->edgeSetFactory, $vertex);
271 12
            $this->vertexMap->put($vertex, $ec);
272
        }
273
        
274 12
        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