forked from graphp/graph
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWalk.php
More file actions
203 lines (181 loc) · 6.22 KB
/
Copy pathWalk.php
File metadata and controls
203 lines (181 loc) · 6.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
<?php
namespace Graphp\Graph;
use Graphp\Graph\Set\Edges;
use Graphp\Graph\Set\Vertices;
use Graphp\Graph\Exception\UnderflowException;
use Graphp\Graph\Exception\InvalidArgumentException;
use Graphp\Graph\Set\DualAggregate;
/**
* Base Walk class
*
* The general term "Walk" bundles the following mathematical concepts:
* walk, path, cycle, circuit, loop, trail, tour, etc.
*
* @link http://en.wikipedia.org/wiki/Path_%28graph_theory%29
* @link http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Walks
* @see Graphp\Graph\Algorithm\Property\WalkProperty for checking special cases, such as cycles, loops, closed trails, etc.
*/
class Walk implements DualAggregate
{
/**
* construct new walk from given start vertex and given array of edges
*
* @param Edges $edges
* @param Vertex $startVertex
* @return Walk
*/
public static function factoryFromEdges(Edges $edges, Vertex $startVertex)
{
$vertices = array($startVertex);
$vertexCurrent = $startVertex;
foreach ($edges as $edge) {
$vertexCurrent = $edge->getVertexToFrom($vertexCurrent);
$vertices []= $vertexCurrent;
}
return new self(new Vertices($vertices), $edges);
}
/**
* create new walk instance between given set of Vertices / array of Vertex instances
*
* @param Vertices $vertices
* @param null|string|callable(Edge):number $orderBy
* @param bool $desc
* @return Walk
* @throws UnderflowException if no vertices were given
* @see Edges::getEdgeOrder() for parameters $by and $desc
*/
public static function factoryFromVertices(Vertices $vertices, $orderBy = null, $desc = false)
{
$edges = array();
$last = NULL;
foreach ($vertices as $vertex) {
// skip first vertex as last is unknown
if ($last !== NULL) {
// pick edge between last vertex and this vertex
/* @var $last Vertex */
if ($orderBy === null) {
$edges []= $last->getEdgesTo($vertex)->getEdgeFirst();
} else {
$edges []= $last->getEdgesTo($vertex)->getEdgeOrder($orderBy, $desc);
}
}
$last = $vertex;
}
if ($last === NULL) {
throw new UnderflowException('No vertices given');
}
return new self($vertices, new Edges($edges));
}
/**
* create new cycle instance with edges between given vertices
*
* @param Vertices $vertices
* @param null|string|callable(Edge):number $orderBy
* @param bool $desc
* @return Walk
* @throws UnderflowException if no vertices were given
* @see Edges::getEdgeOrder() for parameters $by and $desc
* @uses self::factoryFromVertices()
*/
public static function factoryCycleFromVertices(Vertices $vertices, $orderBy = null, $desc = false)
{
$cycle = self::factoryFromVertices($vertices, $orderBy, $desc);
if ($cycle->getEdges()->isEmpty()) {
throw new InvalidArgumentException('Cycle with no edges can not exist');
}
if ($cycle->getVertices()->getVertexFirst() !== $cycle->getVertices()->getVertexLast()) {
throw new InvalidArgumentException('Cycle has to start and end at the same vertex');
}
return $cycle;
}
/**
* create new cycle instance with vertices connected by given edges
*
* @param Edges $edges
* @param Vertex $startVertex
* @return Walk
* @throws InvalidArgumentException if the given array of edges does not represent a valid cycle
* @uses self::factoryFromEdges()
*/
public static function factoryCycleFromEdges(Edges $edges, Vertex $startVertex)
{
$cycle = self::factoryFromEdges($edges, $startVertex);
// ensure this walk is actually a cycle by checking start = end
if ($cycle->getVertices()->getVertexLast() !== $startVertex) {
throw new InvalidArgumentException('The given array of edges does not represent a cycle');
}
return $cycle;
}
/**
* @var Vertices
*/
protected $vertices;
/**
* @var Edges
*/
protected $edges;
protected function __construct(Vertices $vertices, Edges $edges)
{
$this->vertices = $vertices;
$this->edges = $edges;
}
/**
* return original graph
*
* @return Graph
* @uses self::getVertices()
* @uses Vertices::getVertexFirst()
* @uses Vertex::getGraph()
*/
public function getGraph()
{
return $this->vertices->getVertexFirst()->getGraph();
}
/**
* return set of all Edges of walk (in sequence visited in walk, may contain duplicates)
*
* If you need to return set a of all unique Edges of walk, use
* `Walk::getEdges()->getEdgesDistinct()` instead.
*
* @return Edges
*/
public function getEdges()
{
return $this->edges;
}
/**
* return set of all Vertices of walk (in sequence visited in walk, may contain duplicates)
*
* If you need to return set a of all unique Vertices of walk, use
* `Walk::getVertices()->getVerticesDistinct()` instead.
*
* If you need to return the source vertex (first vertex of walk), use
* `Walk::getVertices()->getVertexFirst()` instead.
*
* If you need to return the target/destination vertex (last vertex of walk), use
* `Walk::getVertices()->getVertexLast()` instead.
*
* @return Vertices
*/
public function getVertices()
{
return $this->vertices;
}
/**
* get alternating sequence of vertex, edge, vertex, edge, ..., vertex
*
* @return array
*/
public function getAlternatingSequence()
{
$edges = $this->edges->getVector();
$vertices = $this->vertices->getVector();
$ret = array();
for ($i = 0, $l = \count($this->edges); $i < $l; ++$i) {
$ret []= $vertices[$i];
$ret []= $edges[$i];
}
$ret[] = $vertices[$i];
return $ret;
}
}