diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0298d9..8cf7f7f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Vertex ([#62](https://github.com/clue/graph/issues/62)) ([#62](https://github.com/clue/graph/issues/62)) * 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)). +* Feature: Add `Walk::factoryFromVertices()` ([#64](https://github.com/clue/graph/issues/64)). * Fix: Checking `Walk::isValid()` ([#61](https://github.com/clue/graph/issues/61)) * Fix: Missing import prevented `Algorithm\ShortestPath\MooreBellmanFord::getCycleNegative()` from actually diff --git a/lib/Fhaculty/Graph/Walk.php b/lib/Fhaculty/Graph/Walk.php index 23f04195..0b192801 100644 --- a/lib/Fhaculty/Graph/Walk.php +++ b/lib/Fhaculty/Graph/Walk.php @@ -41,6 +41,42 @@ public static function factoryFromEdges($edges, Vertex $startVertex) return new self($vertices, $edges); } + /** + * create new walk instance between given set of Vertices / array of Vertex instances + * + * @param Vertices|Vertex[] $vertices + * @param int|null $by + * @param boolean $desc + * @return Walk + * @throws UnderflowException if no vertices were given + * @see Edges::getEdgeOrder() for parameters $by and $desc + */ + public static function factoryFromVertices($vertices, $by = null, $desc = false) + { + $edges = array(); + $first = NULL; + $last = NULL; + foreach ($vertices as $vertex) { + // skip first vertex as last is unknown + if ($first === NULL) { + $first = $vertex; + } else { + // pick edge between last vertex and this vertex + if ($by === null) { + $edges []= $last->getEdgesTo($vertex)->getEdgeFirst(); + } else { + $edges []= $last->getEdgesTo($vertex)->getEdgeOrder($by, $desc); + } + } + $last = $vertex; + } + if ($last === NULL) { + throw new UnderflowException('No vertices given'); + } + + return new self($vertices, $edges); + } + /** * create new cycle instance from given predecessor map * @@ -102,41 +138,31 @@ public static function factoryCycleFromPredecessorMap($predecessors, $vertex, $b * @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, $by = null, $desc = false) { - $edges = array(); - $first = NULL; - $last = NULL; - foreach ($vertices as $vertex) { - // skip first vertex as last is unknown - if ($first === NULL) { - $first = $vertex; - } else { - // pick edge between last vertex and this vertex - if ($by === null) { - $edges []= $last->getEdgesTo($vertex)->getEdgeFirst(); - } else { - $edges []= $last->getEdgesTo($vertex)->getEdgeOrder($by, $desc); - } - } - $last = $vertex; - } - if ($last === NULL) { - throw new UnderflowException('No vertices given'); - } + $cycle = self::factoryFromVertices($vertices, $by, $desc); + + $first = $cycle->getVertexSource(); + $last = $cycle->getVertexTarget(); // additional edge from last vertex to first vertex if ($last !== $first) { + $vertices = $cycle->getVertices()->getVector(); + $edges = $cycle->getEdges()->getVector(); + if ($by === null) { $edges []= $last->getEdgesTo($first)->getEdgeFirst(); } else { $edges []= $last->getEdgesTo($first)->getEdgeOrder($by, $desc); } $vertices []= $first; + + $cycle = new self($vertices, $edges); } - return new self($vertices, $edges); + return $cycle; } /** diff --git a/tests/Fhaculty/Graph/WalkTest.php b/tests/Fhaculty/Graph/WalkTest.php index 1dc12ea8..b8f90745 100644 --- a/tests/Fhaculty/Graph/WalkTest.php +++ b/tests/Fhaculty/Graph/WalkTest.php @@ -76,6 +76,14 @@ public function testWalkWithinGraph() $this->assertGraphEquals($graphExpected, $walk->createGraph()); + // construct same partial walk "1 -- 2" + $walkVertices = Walk::factoryFromVertices(array($v1, $v2)); + + $this->assertEquals(2, $walkVertices->getNumberOfVertices()); + $this->assertEquals(1, $walkVertices->getNumberOfEdges()); + + $this->assertGraphEquals($graphExpected, $walkVertices->createGraph()); + return $walk; }