diff --git a/CHANGELOG.md b/CHANGELOG.md index 173e463a..e21a29e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,11 @@ you spot any mistakes. `OutOfBoundsException` for unreachable vertices ([#62](https://github.com/clue/graph/issues/62)) +* BC break: A null Graph (a Graph with no Vertices and thus no Edges) is not a + valid tree (because it is not connected), adjust `Algorithm\Tree\Base::isTree()` + accordingly. + ([#72](https://github.com/clue/graph/issues/72)) + * Feature: Add `Algorithm\ShortestPath::hasVertex(Vertex $vertex)` to check whether a path to the given Vertex exists ([#62](https://github.com/clue/graph/issues/62)). diff --git a/lib/Fhaculty/Graph/Algorithm/Tree/Base.php b/lib/Fhaculty/Graph/Algorithm/Tree/Base.php index 6e9b8fa2..1dbfb675 100644 --- a/lib/Fhaculty/Graph/Algorithm/Tree/Base.php +++ b/lib/Fhaculty/Graph/Algorithm/Tree/Base.php @@ -10,6 +10,7 @@ use Fhaculty\Graph\Exception\UnexpectedValueException; use Fhaculty\Graph\Algorithm\Search\StrictDepthFirst; use Fhaculty\Graph\Algorithm\Degree; +use Fhaculty\Graph\Algorithm\ConnectedComponents; /** * Abstract base class for tree algorithms @@ -18,7 +19,9 @@ * graphs that represent a tree. * * A tree is a connected Graph (single component) with no cycles. Every Tree is - * a Graph, but not every Graph is a Tree. + * a Graph, but not every Graph is a Tree. A null Graph (a Graph with no Vertices + * and thus no Edges) is *NOT* considered a valid Tree, as it is not considered + * connected (@see ConnectedComponents and @link) * * A * / \ @@ -32,6 +35,7 @@ * * @link http://en.wikipedia.org/wiki/Tree_%28graph_theory%29 * @link http://en.wikipedia.org/wiki/Tree_%28data_structure%29 + * @link http://mathoverflow.net/questions/120536/is-the-empty-graph-a-tree * @see Undirected for an implementation of these algorithms on (undirected) trees * @see BaseDirected for an abstract implementation of these algorithms on directed, rooted trees */ diff --git a/lib/Fhaculty/Graph/Algorithm/Tree/BaseDirected.php b/lib/Fhaculty/Graph/Algorithm/Tree/BaseDirected.php index 1fe1dac3..e67e99c8 100644 --- a/lib/Fhaculty/Graph/Algorithm/Tree/BaseDirected.php +++ b/lib/Fhaculty/Graph/Algorithm/Tree/BaseDirected.php @@ -73,16 +73,11 @@ public function getVertexRoot() * checks if this is a tree * * @return boolean - * @uses Vertices::isEmpty() to skip empty Graphs (an empty Graph is a valid tree) * @uses self::getVertexRoot() to get root Vertex to start search from * @uses self::getVerticesSubtree() to count number of vertices connected to root */ public function isTree() { - if ($this->graph->getVertices()->isEmpty()) { - return true; - } - try { $root = $this->getVertexRoot(); } @@ -138,7 +133,7 @@ abstract public function getVerticesChildren(Vertex $vertex); /** * internal helper to get all parents vertices * - * a valid tree vertex only ever has a single parent, expect for the root, + * a valid tree vertex only ever has a single parent, except for the root, * which has none. * * @param Vertex $vertex diff --git a/lib/Fhaculty/Graph/Algorithm/Tree/Undirected.php b/lib/Fhaculty/Graph/Algorithm/Tree/Undirected.php index b25e8674..8f55d4af 100644 --- a/lib/Fhaculty/Graph/Algorithm/Tree/Undirected.php +++ b/lib/Fhaculty/Graph/Algorithm/Tree/Undirected.php @@ -49,14 +49,14 @@ class Undirected extends Tree * checks if this is a tree * * @return boolean - * @uses Vertices::isEmpty() to skip empty Graphs (an empty Graph is a valid tree) + * @uses Vertices::isEmpty() to skip null Graphs (a Graph with no Vertices is *NOT* a valid tree) * @uses Graph::getVertexFirst() to get get get random "root" Vertex to start search from * @uses self::getVerticesSubtreeRecursive() to count number of vertices connected to root */ public function isTree() { if ($this->graph->getVertices()->isEmpty()) { - return true; + return false; } // every vertex can represent a root vertex, so just pick one diff --git a/tests/Fhaculty/Graph/Algorithm/Tree/BaseDirectedTest.php b/tests/Fhaculty/Graph/Algorithm/Tree/BaseDirectedTest.php index 682e51a9..0c433dc1 100644 --- a/tests/Fhaculty/Graph/Algorithm/Tree/BaseDirectedTest.php +++ b/tests/Fhaculty/Graph/Algorithm/Tree/BaseDirectedTest.php @@ -30,12 +30,12 @@ abstract protected function createGraphTree(); */ abstract protected function createGraphParallelEdge(); - public function testEmptyGraph() + public function testNullGraph() { $graph = new Graph(); $tree = $this->createTreeAlg($graph); - $this->assertTrue($tree->isTree()); + $this->assertFalse($tree->isTree()); $this->assertTrue($tree->getVerticesLeaf()->isEmpty()); $this->assertTrue($tree->getVerticesInternal()->isEmpty()); @@ -44,7 +44,7 @@ public function testEmptyGraph() /** * @param BaseDirected $tree - * @depends testEmptyGraph + * @depends testNullGraph * @expectedException UnderflowException */ public function testEmptyGraphDoesNotHaveRootVertex(BaseDirected $tree) @@ -54,7 +54,7 @@ public function testEmptyGraphDoesNotHaveRootVertex(BaseDirected $tree) /** * @param BaseDirected $tree - * @depends testEmptyGraph + * @depends testNullGraph * @expectedException UnderflowException */ public function testEmptyGraphDoesNotHaveDegree(BaseDirected $tree) @@ -64,7 +64,7 @@ public function testEmptyGraphDoesNotHaveDegree(BaseDirected $tree) /** * @param BaseDirected $tree - * @depends testEmptyGraph + * @depends testNullGraph * @expectedException UnderflowException */ public function testEmptyGraphDoesNotHaveHeight(BaseDirected $tree) diff --git a/tests/Fhaculty/Graph/Algorithm/Tree/UndirectedTest.php b/tests/Fhaculty/Graph/Algorithm/Tree/UndirectedTest.php index daa55acd..98c089c5 100644 --- a/tests/Fhaculty/Graph/Algorithm/Tree/UndirectedTest.php +++ b/tests/Fhaculty/Graph/Algorithm/Tree/UndirectedTest.php @@ -11,15 +11,15 @@ protected function createTree(Graph $graph) return new Undirected($graph); } - public function testGraphEmpty() + public function testNullGraph() { $graph = new Graph(); $tree = $this->createTree($graph); - $this->assertTrue($tree->isTree()); - $this->assertSame(array(), $tree->getVerticesInternal()->getVector()); - $this->assertSame(array(), $tree->getVerticesLeaf()->getVector()); + $this->assertFalse($tree->isTree()); + $this->assertTrue($tree->getVerticesInternal()->isEmpty()); + $this->assertTrue($tree->getVerticesLeaf()->isEmpty()); } public function testGraphTrivial()