Skip to content

Commit 8529635

Browse files
committed
Merge branch 'add-vertices-class' (closes PR #48)
Conflicts: CHANGELOG.md
2 parents 90464d2 + fd8750d commit 8529635

72 files changed

Lines changed: 2457 additions & 908 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,41 @@ you spot any mistakes.
66

77
## 0.7.0 (2013-xx-xx)
88

9+
* Feature: Add new `Set\Vertices` and `Set\Edges` classes that handle common
10+
operations on a Set of multiple `Vertex` and `Edge` instances respectively.
11+
([#48](https://github.com/clue/graph/issues/48))
12+
13+
* BC break: Move operations and their corresponding constants concerning Sets
14+
to their corresponding Sets:
15+
16+
| Old name | New name |
17+
|---|---|
18+
| `Edge\Base::getFirst()` | `Set\Edges::getEdgeOrder()` |
19+
| `Edge\Base::getAll()` | `Set\Edges::getEdgesOrder()` |
20+
| `Edge\Base::ORDER_*` | `Set\Edges::ORDER_* |
21+
|---|---|
22+
| `Vertex::getFirst()` | `Set\Vertices::getVertexOrder()` |
23+
| `Vertex::getAll()` | `Set\Vertices::getVerticesOrder()` |
24+
| `Vertex::ORDER_` | `Set\Vertices::ORDER_*` |
25+
26+
* BC break: Each `getVertices*()` and `getEdges*()` method now returns a `Set`
27+
instead of a primitive array of instances. *Most* of the time this should
28+
work without changing your code, because each `Set` implements an `Iterator`
29+
interface and can easily be iterated using `foreach`. However, using a `Set`
30+
instead of a plain array differs when checking its boolean value or
31+
comparing two Sets. I.e. if you happen to want to check if an `Set` is empty,
32+
you now have to use the more explicit syntax `$set->isEmpty()`.
33+
34+
* BC break: `Vertex::getVertices()`, `Vertex::getVerticesEdgeTo()` and
35+
`Vertex::getVerticesEdgeFrom()` now return a `Set\Vertices` instance that
36+
may contain duplicate vertices if parallel (multiple) edges exist. Previously
37+
there was no easy way to detect this situation - this is now the default. If
38+
you also want to get unique / distinct `Vertex` instances, use
39+
`Vertex::getVertices()->getVerticesDistinct()` where applicable.
40+
41+
* BC break: Remove all occurances of `getVerticesId()`, use
42+
`getVertices()->getIds()` instead.
43+
944
* BC break: Merge `Cycle` into `Walk` ([#61](https://github.com/clue/graph/issues/61)).
1045
As such, its static factory methods had to be renamed. Update your references if applicable:
1146

@@ -15,6 +50,12 @@ As such, its static factory methods had to be renamed. Update your references if
1550
| `Cycle::factoryFromVertices()` | `Walk::factoryCycleFromVertices()` |
1651
| `Cycle::factoryFromEdges()` | `Walk::factoryCycleFromEdges()` |
1752

53+
* BC break: Remove `Graph::isEmpty()` because it's not well-defined and might
54+
be confusing. Most literature suggests it should check for existing edges,
55+
whereas the old behavior was to check for existing vertices instead. Use either
56+
of the more transparent methods
57+
`Algorithm\Property\GraphProperty::isNull()` (old behavior) or (where applicable)
58+
`Algorithm\Property\GraphProperty::isEmpty()` ([#59](https://github.com/clue/graph/issues/59)).
1859
* BC break: Each of the above methods (`Walk::factoryCycleFromPredecessorMap()`,
1960
`Walk::factoryCycleFromVertices()`, `Walk::factoryCycleFromEdges()`) now
2061
actually makes sure the returned `Walk` instance is actually a valid Cycle,
@@ -28,6 +69,7 @@ Vertex ([#62](https://github.com/clue/graph/issues/62))
2869
* Feature: Add `Algorithm\ShortestPath::hasVertex(Vertex $vertex)` to check whether
2970
a path to the given Vertex exists ([#62](https://github.com/clue/graph/issues/62)).
3071
* Feature: Support opening GraphViz images on Mac OS X in default image viewer ([#67](https://github.com/clue/graph/issues/67) @onigoetz)
72+
* Feature: Add `Walk::factoryFromVertices()` ([#64](https://github.com/clue/graph/issues/64)).
3173
* Fix: Checking `Walk::isValid()` ([#61](https://github.com/clue/graph/issues/61))
3274
* Fix: Missing import prevented
3375
`Algorithm\ShortestPath\MooreBellmanFord::getCycleNegative()` from actually

lib/Fhaculty/Graph/Algorithm/Bipartit.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function getColors()
5151
$colors = array();
5252

5353
// get color for each vertex
54-
foreach ($this->graph->getVertices() as $vid => $startVertex) {
54+
foreach ($this->graph->getVertices()->getMap() as $vid => $startVertex) {
5555
if (!isset($colors[$vid])) {
5656
$queue = array($startVertex);
5757
// initialize each components color
@@ -65,7 +65,7 @@ public function getColors()
6565
$nextColor = 1-$color;
6666

6767
// scan all vertices connected to this vertex
68-
foreach ($vertex->getVerticesEdge() as $vid => $nextVertex) {
68+
foreach ($vertex->getVerticesEdge()->getMap() as $vid => $nextVertex) {
6969
// color unknown, so expect next color for this vertex
7070
if (!isset($colors[$vid])) {
7171
$colors[$vid] = $nextColor;
@@ -92,7 +92,7 @@ public function getColorVertices()
9292
$colors = $this->getColors();
9393
$ret = array(0 => array(), 1 => array());
9494

95-
foreach ($this->graph->getVertices() as $vid => $vertex) {
95+
foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {
9696
$ret[$colors[$vid]][$vid] = $vertex;
9797
}
9898

@@ -113,7 +113,7 @@ public function createGraphGroups()
113113
$colors = $this->getColors();
114114

115115
$graph = $this->graph->createGraphClone();
116-
foreach ($graph->getVertices() as $vid => $vertex) {
116+
foreach ($graph->getVertices()->getMap() as $vid => $vertex) {
117117
$vertex->setGroup($colors[$vid]);
118118
}
119119

lib/Fhaculty/Graph/Algorithm/Complete.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class Complete extends BaseGraph
2626
public function isComplete()
2727
{
2828
// copy of array (separate iterator but same vertices)
29-
$c = $vertices = $this->graph->getVertices();
29+
$c = $vertices = $this->graph->getVertices()->getVector();
3030
// from each vertex
3131
foreach ($vertices as $vertex) {
3232
// to each vertex

lib/Fhaculty/Graph/Algorithm/ConnectedComponents.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class ConnectedComponents extends BaseGraph
2424
* @param Vertex $vertex
2525
* @return Graph
2626
* @throws InvalidArgumentException if given vertex is not from same graph
27-
* @uses AlgorithmSearchBreadthFirst::getVerticesIds()
27+
* @uses AlgorithmSearchBreadthFirst::getVertices()
2828
* @uses Graph::createGraphCloneVertices()
2929
*/
3030
public function createGraphComponentVertex(Vertex $vertex)
@@ -36,6 +36,11 @@ public function createGraphComponentVertex(Vertex $vertex)
3636
return $this->graph->createGraphCloneVertices($this->createSearch($vertex)->getVertices());
3737
}
3838

39+
/**
40+
*
41+
* @param Vertex $vertex
42+
* @return SearchBreadthFirst
43+
*/
3944
private function createSearch(Vertex $vertex)
4045
{
4146
$alg = new SearchBreadthFirst($vertex);
@@ -84,20 +89,20 @@ public function isSingle()
8489
*
8590
* @return int number of components
8691
* @uses Graph::getVertices()
87-
* @uses AlgorithmSearchBreadthFirst::getVerticesIds()
92+
* @uses AlgorithmSearchBreadthFirst::getVertices()
8893
*/
8994
public function getNumberOfComponents()
9095
{
9196
$visitedVertices = array();
9297
$components = 0;
9398

9499
// for each vertices
95-
foreach ($this->graph->getVertices() as $vid => $vertex) {
100+
foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {
96101
// did I visit this vertex before?
97102
if (!isset($visitedVertices[$vid])) {
98103

99104
// get all vertices of this component
100-
$newVertices = $this->createSearch($vertex)->getVerticesIds();
105+
$newVertices = $this->createSearch($vertex)->getVertices()->getIds();
101106

102107
++$components;
103108

@@ -125,7 +130,7 @@ public function createGraphsComponents()
125130
$graphs = array();
126131

127132
// for each vertices
128-
foreach ($this->graph->getVertices() as $vid => $vertex) {
133+
foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {
129134
// did I visit this vertex before?
130135
if (!isset($visitedVertices[$vid])) {
131136

@@ -134,7 +139,7 @@ public function createGraphsComponents()
134139
$newVertices = $alg->getVertices();
135140

136141
// mark the vertices of this component as visited
137-
foreach ($newVertices as $vid => $unusedVertex) {
142+
foreach ($newVertices->getIds() as $vid) {
138143
$visitedVertices[$vid] = true;
139144
}
140145

lib/Fhaculty/Graph/Algorithm/Degree.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Fhaculty\Graph\Graph;
77
use Fhaculty\Graph\Vertex;
88
use Fhaculty\Graph\Exception\UnexpectedValueException;
9+
use Fhaculty\Graph\Set\Vertices;
910

1011
/**
1112
* Basic algorithms for working with the degrees of Graphs.
@@ -49,25 +50,25 @@ public function getDegree()
4950
*
5051
* @return int
5152
* @throws Exception if graph is empty or directed
52-
* @uses Vertex::getFirst()
53+
* @uses Vertices::getVertexOrder()
5354
* @uses self::getDegreeVertex()
5455
*/
5556
public function getDegreeMin()
5657
{
57-
return $this->getDegreeVertex(Vertex::getFirst($this->graph->getVertices(), Vertex::ORDER_DEGREE));
58+
return $this->getDegreeVertex($this->graph->getVertices()->getVertexOrder(Vertices::ORDER_DEGREE));
5859
}
5960

6061
/**
6162
* get maximum degree of vertices
6263
*
6364
* @return int
6465
* @throws Exception if graph is empty or directed
65-
* @uses Vertex::getFirst()
66+
* @uses Vertices::getVertexOrder()
6667
* @uses self::getDegreeVertex()
6768
*/
6869
public function getDegreeMax()
6970
{
70-
return $this->getDegreeVertex(Vertex::getFirst($this->graph->getVertices(), Vertex::ORDER_DEGREE, true));
71+
return $this->getDegreeVertex($this->graph->getVertices()->getVertexOrder(Vertices::ORDER_DEGREE, true));
7172
}
7273

7374
/**
@@ -79,7 +80,7 @@ public function getDegreeMax()
7980
public function isRegular()
8081
{
8182
// an empty graph is considered regular
82-
if ($this->graph->isEmpty()) {
83+
if ($this->graph->getVertices()->isEmpty()) {
8384
return true;
8485
}
8586
try {
@@ -174,7 +175,7 @@ public function getDegreeVertex(Vertex $vertex)
174175
*/
175176
public function isVertexIsolated(Vertex $vertex)
176177
{
177-
return !$vertex->getEdges();
178+
return $vertex->getEdges()->isEmpty();
178179
}
179180

180181
/**

lib/Fhaculty/Graph/Algorithm/DetectNegativeCycle.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,22 @@ public function hasCycleNegative()
3737
*
3838
* @return Walk
3939
* @throws UnderflowException if there's no negative cycle
40-
* @uses AlgorithmSpMooreBellmanFord::getVerticesId()
40+
* @uses AlgorithmSpMooreBellmanFord::getVertices()
4141
*/
4242
public function getCycleNegative()
4343
{
4444
// remember vertices already visited, as they can not lead to a new cycle
4545
$verticesVisited = array();
4646
// check for all vertices
47-
foreach ($this->graph->getVertices() as $vid => $vertex) {
47+
foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {
4848
// skip vertices already visited
4949
if (!isset($verticesVisited[$vid])) {
5050
// start MBF algorithm on current vertex
5151
$alg = new SpMooreBellmanFord($vertex);
5252

5353
try {
5454
// try to get all connected vertices (or throw new cycle)
55-
foreach ($alg->getVerticesId() as $vid) {
55+
foreach ($alg->getVertices()->getIds() as $vid) {
5656
// getting connected vertices succeeded, so skip over all of them
5757
$verticesVisited[$vid] = true;
5858
// no cycle found, check next vertex...

lib/Fhaculty/Graph/Algorithm/Groups.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Fhaculty\Graph\Algorithm\BaseGraph;
66
use Fhaculty\Graph\Graph;
7+
use Fhaculty\Graph\Set\Vertices;
78

89
class Groups extends BaseGraph
910
{
@@ -66,21 +67,21 @@ public function getGroups()
6667
}
6768

6869
/**
69-
* get array of all vertices in the given group
70+
* get set of all Vertices in the given group
7071
*
7172
* @param int $group
72-
* @return Vertex[]
73+
* @return Vertices
7374
* @uses Vertex::getGroup()
7475
*/
7576
public function getVerticesGroup($group)
7677
{
7778
$vertices = array();
78-
foreach ($this->graph->getVertices() as $vid => $vertex) {
79+
foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {
7980
if ($vertex->getGroup() === $group) {
8081
$vertices[$vid] = $vertex;
8182
}
8283
}
8384

84-
return $vertices;
85+
return new Vertices($vertices);
8586
}
8687
}

lib/Fhaculty/Graph/Algorithm/MaxFlow/EdmondsKarp.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Fhaculty\Graph\Graph;
1818
use Fhaculty\Graph\Vertex;
1919
use Fhaculty\Graph\Edge\Base as Edge;
20+
use Fhaculty\Graph\Set\Edges;
2021
use Fhaculty\Graph\Algorithm\Base;
2122
use Fhaculty\Graph\Algorithm\ResidualGraph;
2223
use Fhaculty\Graph\Exception;
@@ -86,7 +87,7 @@ public function createGraph()
8687
// If path exists add the new flow to graph
8788
if ($pathFlow) {
8889
// 2. get max flow from path
89-
$maxFlowValue = Edge::getFirst($pathFlow->getEdges(), Edge::ORDER_CAPACITY)->getCapacity();
90+
$maxFlowValue = $pathFlow->getEdges()->getEdgeOrder(Edges::ORDER_CAPACITY)->getCapacity();
9091

9192
// 3. add flow to path
9293
foreach ($pathFlow->getEdges() as $edge) {

lib/Fhaculty/Graph/Algorithm/MaximumMatching/Base.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Fhaculty\Graph\Algorithm\BaseGraph;
66
use Fhaculty\Graph\Graph;
77
use Fhaculty\Graph\Edge\Base as Edge;
8+
use Fhaculty\Graph\Set\Edges;
89

910
abstract class Base extends BaseGraph
1011
{
@@ -35,7 +36,7 @@ public function createGraph()
3536
/**
3637
* create new resulting graph with minimum-cost flow on edges
3738
*
38-
* @return Edge[]
39+
* @return Edges
3940
*/
4041
abstract public function getEdges();
4142
}

lib/Fhaculty/Graph/Algorithm/MaximumMatching/Flow.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Fhaculty\Graph\Algorithm\MaxFlow\EdmondsKarp as MaxFlowEdmondsKarp;
1212
use Fhaculty\Graph\Algorithm\Groups;
1313
use Fhaculty\Graph\Exception;
14+
use Fhaculty\Graph\Set\Edges;
1415

1516
class Flow extends Base
1617
{
@@ -29,11 +30,6 @@ public function getEdges()
2930
// create temporary flow graph with supersource and supersink
3031
$graphFlow = $this->graph->createGraphCloneEdgeless();
3132

32-
// get all vertices
33-
$vertices = $graphFlow->getVertices();
34-
// above $vertices does NOT contain supersource and supersink, because
35-
// we want to skip over them as they do not have a partition assigned
36-
3733
$superSource = $graphFlow->createVertex()->setLayoutAttribute('label', 's*');
3834
$superSink = $graphFlow->createVertex()->setLayoutAttribute('label', 't*');
3935

@@ -42,7 +38,10 @@ public function getEdges()
4238
$groupB = $groups[1];
4339

4440
// connect supersource s* to set A and supersink t* to set B
45-
foreach ($vertices as $vertex) {
41+
foreach ($graphFlow->getVertices() as $vertex) {
42+
// we want to skip over supersource & supersink as they do not have a partition assigned
43+
if ($vertex === $superSource || $vertex === $superSink) continue;
44+
4645
$group = $vertex->getGroup();
4746

4847
// source
@@ -83,6 +82,6 @@ public function getEdges()
8382
}
8483
}
8584

86-
return $returnEdges;
85+
return new Edges($returnEdges);
8786
}
8887
}

0 commit comments

Comments
 (0)