diff --git a/src/Property/GraphProperty.php b/src/Property/GraphProperty.php index d83b7a6..6132433 100644 --- a/src/Property/GraphProperty.php +++ b/src/Property/GraphProperty.php @@ -48,4 +48,47 @@ public function isTrivial() { return ($this->graph->getEdges()->isEmpty() && \count($this->graph->getVertices()) === 1); } + + /** + * checks whether this graph is acyclic (directed graph with no cycles) + * using the Kahn algorithm + * + * @return boolean + * @link https://en.wikipedia.org/wiki/Directed_acyclic_graph + */ + public function isAcyclic() + { + $vertices = $this->graph->getVertices(); + $nVertices = count($vertices); + $visited = 0; + $inDegree = array(); + $stack = array(); + + foreach($vertices as $vert){ + $deg=count($vert->getEdgesIn()); + $inDegree[$vert->getId()]=$deg; + if($deg==0){ + \array_push($stack,$vert); + } + } + + while(!(empty($stack))){ + $n = array_pop($stack); + $visited++; + foreach($n->getEdgesOut() as $e){ + $m = $e->getVertexEnd(); + $inDegree[$m->getId()]--; + if($inDegree[$m->getId()]==0){ + \array_push($stack,$m); + } + } + } + + if($visited==$nVertices){ + return true; + } + else{ + return false; + } + } } diff --git a/tests/Property/PropertyGraphTest.php b/tests/Property/PropertyGraphTest.php index 32e0374..66cc3da 100644 --- a/tests/Property/PropertyGraphTest.php +++ b/tests/Property/PropertyGraphTest.php @@ -14,6 +14,7 @@ public function testEmptyIsEdgeless() $this->assertTrue($alg->isNull()); $this->assertTrue($alg->isEdgeless()); $this->assertFalse($alg->isTrivial()); + $this->assertTrue($alg->isAcyclic()); } public function testSingleVertexIsTrivial() @@ -26,5 +27,50 @@ public function testSingleVertexIsTrivial() $this->assertFalse($alg->isNull()); $this->assertTrue($alg->isEdgeless()); $this->assertTrue($alg->isTrivial()); + $this->assertTrue($alg->isAcyclic()); + } + + public function testUndirectedIsAcyclic() + { + $graph = new Graph(); + $graph->createVertex(1)->createEdge($graph->createVertex(2)); + + $alg = new GraphProperty($graph); + + $this->assertFalse($alg->isNull()); + $this->assertFalse($alg->isEdgeless()); + $this->assertFalse($alg->isTrivial()); + $this->assertFalse($alg->isAcyclic()); + } + + public function testGraphSimpleIsAcyclic() + { + $graph = new Graph(); + $graph->createVertex(1)->createEdgeTo($graph->createVertex(2)); + + $alg = new GraphProperty($graph); + + $this->assertFalse($alg->isNull()); + $this->assertFalse($alg->isEdgeless()); + $this->assertFalse($alg->isTrivial()); + $this->assertTrue($alg->isAcyclic()); + } + + public function testGraphWithCycleIsAcyclic() + { + $graph = new Graph(); + $vertexOne = $graph->createVertex(1); + $vertexTwo = $graph->createVertex(2); + $vertexThree = $graph->createVertex(3); + $vertexOne->createEdgeTo($vertexTwo); + $vertexTwo->createEdgeTo($vertexThree); + $vertexThree->createEdgeTo($vertexOne); + + $alg = new GraphProperty($graph); + + $this->assertFalse($alg->isNull()); + $this->assertFalse($alg->isEdgeless()); + $this->assertFalse($alg->isTrivial()); + $this->assertFalse($alg->isAcyclic()); } }