diff --git a/src/Edge.php b/src/Edge.php index e4111ba1..807269cd 100644 --- a/src/Edge.php +++ b/src/Edge.php @@ -2,37 +2,36 @@ namespace Graphp\Graph; -use Graphp\Graph\Set\Vertices; -use Graphp\Graph\Set\VerticesAggregate; - /** * Abstract base for `EdgeUndirected` and `EdgeDirected` containing common interfaces and behavior for all edges. * * @see EdgeUndirected * @see EdgeDirected */ -abstract class Edge extends Entity implements VerticesAggregate +abstract class Edge extends Entity { protected $attributes = array(); /** - * get Vertices that are a target of this edge + * get vertices that are a target of this edge * - * @return Vertices + * @psalm-return list + * @return Vertex[] */ abstract public function getVerticesTarget(); /** - * get Vertices that are the start of this edge + * get vertices that are the start of this edge * - * @return Vertices + * @psalm-return list + * @return Vertex[] */ abstract public function getVerticesStart(); /** * return true if this edge is an outgoing edge of the given vertex (i.e. the given vertex is a valid start vertex of this edge) * - * @param Vertex $startVertex + * @param Vertex $startVertex * @return bool * @uses Vertex::getVertexToFrom() */ @@ -41,7 +40,7 @@ abstract public function hasVertexStart(Vertex $startVertex); /** * return true if this edge is an ingoing edge of the given vertex (i . e. the given vertex is a valid end vertex of this edge) * - * @param Vertex $targetVertex + * @param Vertex $targetVertex * @return bool * @uses Vertex::getVertexFromTo() */ @@ -77,11 +76,12 @@ abstract public function getVertexToFrom(Vertex $startVertex); abstract public function getVertexFromTo(Vertex $endVertex); /** - * get set of all Vertices this edge connects + * get list of all vertices this edge connects * - * @return Vertices + * @psalm-return list + * @return Vertex[] */ - //abstract public function getVertices(); + abstract public function getVertices(); /** * get graph instance this edge is attached to @@ -90,7 +90,11 @@ abstract public function getVertexFromTo(Vertex $endVertex); */ public function getGraph() { - return $this->getVertices()->getVertexFirst()->getGraph(); + $vertices = $this->getVertices(); + $vertex = \reset($vertices); + \assert($vertex instanceof Vertex); + + return $vertex->getGraph(); } /** diff --git a/src/EdgeDirected.php b/src/EdgeDirected.php index e30ac165..f1e570fc 100644 --- a/src/EdgeDirected.php +++ b/src/EdgeDirected.php @@ -2,8 +2,6 @@ namespace Graphp\Graph; -use Graphp\Graph\Set\Vertices; - class EdgeDirected extends Edge { /** @@ -47,17 +45,17 @@ public function __construct(Vertex $from, Vertex $to, array $attributes = array( public function getVerticesTarget() { - return new Vertices(array($this->to)); + return array($this->to); } public function getVerticesStart() { - return new Vertices(array($this->from)); + return array($this->from); } public function getVertices() { - return new Vertices(array($this->from, $this->to)); + return array($this->from, $this->to); } /** diff --git a/src/EdgeUndirected.php b/src/EdgeUndirected.php index 76c25a52..4ea1bc73 100644 --- a/src/EdgeUndirected.php +++ b/src/EdgeUndirected.php @@ -2,8 +2,6 @@ namespace Graphp\Graph; -use Graphp\Graph\Set\Vertices; - class EdgeUndirected extends Edge { /** @@ -47,17 +45,17 @@ public function __construct(Vertex $a, Vertex $b, array $attributes = array()) public function getVerticesTarget() { - return new Vertices(array($this->b, $this->a)); + return array($this->b, $this->a); } public function getVerticesStart() { - return new Vertices(array($this->a, $this->b)); + return array($this->a, $this->b); } public function getVertices() { - return new Vertices(array($this->a, $this->b)); + return array($this->a, $this->b); } public function isConnection(Vertex $from, Vertex $to) diff --git a/src/Graph.php b/src/Graph.php index 63cbfcf3..3cb88b9a 100644 --- a/src/Graph.php +++ b/src/Graph.php @@ -2,11 +2,7 @@ namespace Graphp\Graph; -use Graphp\Graph\Set\DualAggregate; -use Graphp\Graph\Set\Edges; -use Graphp\Graph\Set\Vertices; - -class Graph extends Entity implements DualAggregate +class Graph extends Entity { protected $vertices = array(); protected $edges = array(); @@ -20,23 +16,25 @@ public function __construct(array $attributes = array()) } /** - * return set of Vertices added to this graph + * return list of all vertices added to this graph * - * @return Vertices + * @psalm-return list + * @return Vertex[] */ public function getVertices() { - return new Vertices($this->vertices); + return $this->vertices; } /** - * return set of ALL Edges added to this graph + * return list of all edges added to this graph * - * @return Edges + * @psalm-return list + * @return Edge[] */ public function getEdges() { - return new Edges($this->edges); + return $this->edges; } /** @@ -97,7 +95,7 @@ public function createEdgeDirected(Vertex $source, Vertex $target, array $attrib */ public function withoutVertex(Vertex $vertex) { - return $this->withoutVertices(new Vertices(array($vertex))); + return $this->withoutVertices(array($vertex)); } /** @@ -107,10 +105,10 @@ public function withoutVertex(Vertex $vertex) * silently be ignored. If neither of the vertices can be found in this graph, * the returned graph will be identical. * - * @param Vertices $vertices + * @param Vertex[] $vertices * @return self */ - public function withoutVertices(Vertices $vertices) + public function withoutVertices(array $vertices) { // keep copy of original vertices and edges and temporarily remove all $vertices and their adjacent edges $originalEdges = $this->edges; @@ -133,7 +131,7 @@ public function withoutVertices(Vertices $vertices) // clone graph with vertices/edges temporarily removed, then restore $clone = clone $this; - $this->edges= $originalEdges; + $this->edges = $originalEdges; $this->vertices = $originalVertices; return $clone; @@ -150,7 +148,7 @@ public function withoutVertices(Vertices $vertices) */ public function withoutEdge(Edge $edge) { - return $this->withoutEdges(new Edges(array($edge))); + return $this->withoutEdges(array($edge)); } /** @@ -160,10 +158,10 @@ public function withoutEdge(Edge $edge) * silently be ignored. If neither of the edges can be found in this graph, * the returned graph will be identical. * - * @param Edges $edges + * @param Edge[] $edges * @return self */ - public function withoutEdges(Edges $edges) + public function withoutEdges(array $edges) { // keep copy of original edges and temporarily remove all $edges $original = $this->edges; @@ -236,7 +234,7 @@ public function __clone() \assert($originalEdge instanceof Edge); // use map to match old vertex hashes to new vertex objects - $vertices = $originalEdge->getVertices()->getVector(); + $vertices = $originalEdge->getVertices(); $v1 = $map[\spl_object_hash($vertices[0])]; $v2 = $map[\spl_object_hash($vertices[1])]; diff --git a/src/Set/DualAggregate.php b/src/Set/DualAggregate.php deleted file mode 100644 index 5167aba8..00000000 --- a/src/Set/DualAggregate.php +++ /dev/null @@ -1,27 +0,0 @@ -edges = $edges; - } - - /** - * get array index for given Edge - * - * @param Edge $edge - * @throws \OutOfBoundsException - * @return mixed - */ - public function getIndexEdge(Edge $edge) - { - $id = \array_search($edge, $this->edges, true); - if ($id === false) { - throw new \OutOfBoundsException('Given edge does NOT exist'); - } - return $id; - } - - /** - * return first Edge in this set of Edges - * - * some algorithms do not need a particular edge, but merely a (random) - * starting point. this is a convenience function to just pick the first - * edge from the list of known edges. - * - * @return Edge first Edge in this set of Edges - * @throws \UnderflowException if set is empty - * @see self::getEdgeOrder() if you need to apply ordering first - */ - public function getEdgeFirst() - { - if (!$this->edges) { - throw new \UnderflowException('Does not contain any edges'); - } - \reset($this->edges); - - return \current($this->edges); - } - - /** - * return last Edge in this set of Edges - * - * @return Edge last Edge in this set of Edges - * @throws \UnderflowException if set is empty - */ - public function getEdgeLast() - { - if (!$this->edges) { - throw new \UnderflowException('Does not contain any edges'); - } - \end($this->edges); - - return \current($this->edges); - } - - /** - * return random Edge in this set of Edges - * - * @return Edge random Edge in this set of Edges - * @throws \UnderflowException if set is empty - * @see self::getEdgesShuffled() - */ - public function getEdgeRandom() - { - if (!$this->edges) { - throw new \UnderflowException('Does not contain any edges'); - } - - return $this->edges[\array_rand($this->edges)]; - } - - /** - * return Edge at given array index - * - * @param mixed $index - * @throws \OutOfBoundsException if the given index does not exist - * @return Edge - */ - public function getEdgeIndex($index) - { - if (!isset($this->edges[$index])) { - throw new \OutOfBoundsException('Invalid edge index'); - } - return $this->edges[$index]; - } - - /** - * return first Edge that matches the given callback filter function - * - * @param callable $callbackCheck - * @return Edge - * @throws \UnderflowException if no Edge matches the given callback filter function - * @uses self::getEdgeMatchOrNull() - * @see self::getEdgesMatch() if you want to return *all* Edges that match - */ - public function getEdgeMatch($callbackCheck) - { - $ret = $this->getEdgeMatchOrNull($callbackCheck); - if ($ret === null) { - throw new \UnderflowException('No edge found'); - } - return $ret; - } - - /** - * checks whethere there's an Edge that matches the given callback filter function - * - * @param callable $callbackCheck - * @return bool - * @see self::getEdgeMatch() to return the Edge instance that matches the given callback filter function - * @uses self::getEdgeMatchOrNull() - */ - public function hasEdgeMatch($callbackCheck) - { - return ($this->getEdgeMatchOrNull($callbackCheck) !== null); - } - - /** - * get a new set of Edges that match the given callback filter function - * - * This only keeps Edge elements if the $callbackCheck returns a bool - * true and filters out everything else. - * - * Edge index positions will be left unchanged. - * - * @param callable $callbackCheck - * @return Edges a new Edges instance - * @see self::getEdgeMatch() - */ - public function getEdgesMatch($callbackCheck) - { - return new static(\array_filter($this->edges, $callbackCheck)); - } - - /** - * get new set of Edges ordered by given criterium $orderBy - * - * Edge index positions will be left unchanged. - * - * @param string|callable(Edge):number $orderBy criterium to sort by. see edge attribute names or custom callable - * @param bool $desc whether to return biggest first (true) instead of smallest first (default:false) - * @return Edges a new Edges set ordered by the given $orderBy criterium - */ - public function getEdgesOrder($orderBy, $desc = false) - { - $callback = $this->getCallback($orderBy); - $array = $this->edges; - - \uasort($array, function (Edge $va, Edge $vb) use ($callback, $desc) { - $ra = $callback($desc ? $vb : $va); - $rb = $callback($desc ? $va : $vb); - - if ($ra < $rb) { - return -1; - } elseif ($ra > $rb) { - return 1; - } else { - return 0; - } - }); - - return new static($array); - } - - - /** - * get new Set of Edges shuffled by random order - * - * Edge index positions will be left unchanged. - * - * @return Edges a new Edges set shuffled by random order - * @see self::getEdgesOrder() - * @see self::getEdgeRandom() - */ - public function getEdgesShuffled() - { - // shuffle the edge positions - $keys = \array_keys($this->edges); - \shuffle($keys); - - // re-order according to shuffled edge positions - $edges = array(); - foreach ($keys as $key) { - $edges[$key] = $this->edges[$key]; - } - - return new static($edges); - } - - /** - * get first edge ordered by given criterium $orderBy - * - * @param string|callable(Edge):number $orderBy criterium to sort by. see edge attribute names or custom callable - * @param bool $desc whether to return biggest (true) instead of smallest (default:false) - * @return Edge - * @throws \UnderflowException if no edges exist - */ - public function getEdgeOrder($orderBy, $desc=false) - { - if (!$this->edges) { - throw new \UnderflowException('No edge found'); - } - - $callback = $this->getCallback($orderBy); - - $ret = NULL; - $best = NULL; - foreach ($this->edges as $edge) { - $now = $callback($edge); - - if ($ret === NULL || ($desc && $now > $best) || (!$desc && $now < $best)) { - $ret = $edge; - $best = $now; - } - } - - return $ret; - } - - /** - * return self reference to Set of Edges - * - * @return Edges - */ - public function getEdges() - { - return $this; - } - - /** - * get a new set of Edges where each Edge is distinct/unique - * - * @return Edges a new Edges instance - */ - public function getEdgesDistinct() - { - $edges = array(); - foreach ($this->edges as $edge) { - // filter duplicate edges - if (!\in_array($edge, $edges, true)) { - $edges []= $edge; - } - } - - return new Edges($edges); - } - - /** - * get intersection of Edges with given other Edges - * - * The intersection contains all Edge instances that are present in BOTH - * this set of Edges and the given set of other Edges. - * - * Edge index/keys will be preserved from original array. - * - * Duplicate Edge instances will be kept if the corresponding number of - * Edge instances is also found in $otherEdges. - * - * @param Edges $otherEdges - * @return Edges a new Edges set - */ - public function getEdgesIntersection(Edges $otherEdges) - { - $otherArray = \iterator_to_array($otherEdges, false); - - $edges = array(); - foreach ($this->edges as $eid => $edge) { - $i = \array_search($edge, $otherArray, true); - - if ($i !== false) { - // remove from other array in order to check for duplicate matches - unset($otherArray[$i]); - - $edges[$eid] = $edge; - } - } - - return new static($edges); - } - - /** - * return array of Edge instances - * - * @return Edge[] - */ - public function getVector() - { - return \array_values($this->edges); - } - - /** - * count number of Edges - * - * @return int - * @see self::isEmpty() - */ - public function count() - { - return \count($this->edges); - } - - /** - * check whether this Set of Edges is empty - * - * A Set if empty if no single Edge instance is added. This is faster - * than calling `count() === 0`. - * - * @return bool - */ - public function isEmpty() - { - return !$this->edges; - } - - /** - * get Iterator - * - * This method implements the IteratorAggregate interface and allows this - * Set of Edges to be used in foreach loops. - * - * @return \IteratorIterator - */ - public function getIterator() - { - return new \IteratorIterator(new \ArrayIterator($this->edges)); - } - - /** - * call given $callback on each Edge and sum their results - * - * @param string|callable(Edge):number $callback callback to sum by. See edge attribute names or custom callback - * @return number - * @uses self::getCallback() - */ - public function getSumCallback($callback) - { - $callback = $this->getCallback($callback); - - $sum = 0; - foreach ($this->edges as $edge) { - $sum += $callback($edge); - } - return $sum; - } - - private function getEdgeMatchOrNull($callbackCheck) - { - $callbackCheck = $this->getCallback($callbackCheck); - - foreach ($this->edges as $edge) { - if ($callbackCheck($edge)) { - return $edge; - } - } - return null; - } - - /** - * get callback/Closure to be called on Edge instances for given callback identifier - * - * @param string|callable(Edge):number $callback - * @return callable(Edge):number - */ - private function getCallback($callback) - { - if (\is_callable($callback)) { - if (\is_array($callback)) { - $callback = function (Edge $edge) use ($callback) { - return \call_user_func($callback, $edge); - }; - } - return $callback; - } - - return function (Edge $edge) use ($callback) { - return $edge->getAttribute($callback); - }; - - } -} diff --git a/src/Set/EdgesAggregate.php b/src/Set/EdgesAggregate.php deleted file mode 100644 index c642f1dd..00000000 --- a/src/Set/EdgesAggregate.php +++ /dev/null @@ -1,14 +0,0 @@ -vertices = $vertices; - } - - /** - * get array index for given Vertex - * - * not every set of Vertices represents a map, as such array index and - * Vertex ID do not necessarily have to match. - * - * @param Vertex $vertex - * @throws \OutOfBoundsException - * @return mixed - */ - public function getIndexVertex(Vertex $vertex) - { - $id = \array_search($vertex, $this->vertices, true); - if ($id === false) { - throw new \OutOfBoundsException('Given vertex does NOT exist'); - } - return $id; - } - - /** - * return first Vertex in this set of Vertices - * - * some algorithms do not need a particular vertex, but merely a (random) - * starting point. this is a convenience function to just pick the first - * vertex from the list of known vertices. - * - * @return Vertex first Vertex in this set of Vertices - * @throws \UnderflowException if set is empty - * @see self::getVertexOrder() if you need to apply ordering first - */ - public function getVertexFirst() - { - if (!$this->vertices) { - throw new \UnderflowException('Does not contain any vertices'); - } - \reset($this->vertices); - - return \current($this->vertices); - } - - /** - * return last Vertex in this set of Vertices - * - * @return Vertex last Vertex in this set of Vertices - * @throws \UnderflowException if set is empty - */ - public function getVertexLast() - { - if (!$this->vertices) { - throw new \UnderflowException('Does not contain any vertices'); - } - \end($this->vertices); - - return \current($this->vertices); - } - - /** - * returns random Vertex in this set of Vertices - * - * @return Vertex random Vertex in this set of Vertices - * @throws \UnderflowException if set is empty - * @see self::getVerticesShuffled() - */ - public function getVertexRandom() - { - if (!$this->vertices) { - throw new \UnderflowException('Does not contain any vertices'); - } - - return $this->vertices[\array_rand($this->vertices)]; - } - - /** - * return first Vertex that matches the given callback filter function - * - * @param callable $callbackCheck - * @return Vertex - * @throws \UnderflowException if no Vertex matches the given callback filter function - * @uses self::getVertexMatchOrNull() - * @see self::getVerticesMatch() if you want to return *all* Vertices that match - */ - public function getVertexMatch($callbackCheck) - { - $ret = $this->getVertexMatchOrNull($callbackCheck); - if ($ret === null) { - throw new \UnderflowException('No vertex found'); - } - return $ret; - } - - /** - * checks whether there's a Vertex that matches the given callback filter function - * - * @param callable $callbackCheck - * @return bool - * @see self::getVertexMatch() to return the Vertex instance that matches the given callback filter function - * @uses self::getVertexMatchOrNull() - */ - public function hasVertexMatch($callbackCheck) - { - return ($this->getVertexMatchOrNull($callbackCheck) !== null); - } - - /** - * get a new set of Vertices that match the given callback filter function - * - * This only keeps Vertex elements if the $callbackCheck returns a bool - * true and filters out everything else. - * - * Vertex index positions will be left unchanged, so if you call this method - * on a VerticesMap, it will also return a VerticesMap. - * - * @param callable $callbackCheck - * @return Vertices a new Vertices instance - * @see self::getVertexMatch() - */ - public function getVerticesMatch($callbackCheck) - { - return new static(\array_filter($this->vertices, $callbackCheck)); - } - - /** - * get new Set of Vertices ordered by given criterium $orderBy - * - * Vertex index positions will be left unchanged, so if you call this method - * on a VerticesMap, it will also return a VerticesMap. - * - * @param string|callable(Vertex):number $orderBy criterium to sort by. see vertex attribute names or custom callback - * @param bool $desc whether to return biggest first (true) instead of smallest first (default:false) - * @return Vertices a new Vertices set ordered by the given $orderBy criterium - * @see self::getVertexOrder() - */ - public function getVerticesOrder($orderBy, $desc = false) - { - $callback = $this->getCallback($orderBy); - $array = $this->vertices; - - \uasort($array, function (Vertex $va, Vertex $vb) use ($callback, $desc) { - $ra = $callback($desc ? $vb : $va); - $rb = $callback($desc ? $va : $vb); - - if ($ra < $rb) { - return -1; - } elseif ($ra > $rb) { - return 1; - } else { - return 0; - } - }); - - return new static($array); - } - - /** - * get new Set of Vertices shuffled by random order - * - * Vertex index positions will be left unchanged, so if you call this method - * on a VerticesMap, it will also return a VerticesMap. - * - * @return Vertices a new Vertices set shuffled by random order - * @see self::getVerticesOrder() - * @see self::getVertexRandom() - */ - public function getVerticesShuffled() - { - // shuffle the vertex positions - $keys = \array_keys($this->vertices); - \shuffle($keys); - - // re-order according to shuffled vertex positions - $vertices = array(); - foreach ($keys as $key) { - $vertices[$key] = $this->vertices[$key]; - } - - return new static($vertices); - } - - /** - * get intersection of Vertices with given other Vertices - * - * The intersection contains all Vertex instances that are present in BOTH - * this set of Vertices and the given set of other Vertices. - * - * Vertex index/keys will be preserved from original array. - * - * Duplicate Vertex instances will be kept if the corresponding number of - * Vertex instances is also found in $otherVertices. - * - * @param Vertices $otherVertices - * @return Vertices a new Vertices set - */ - public function getVerticesIntersection(Vertices $otherVertices) - { - $otherArray = \iterator_to_array($otherVertices, false); - - $vertices = array(); - foreach ($this->vertices as $vid => $vertex) { - $i = \array_search($vertex, $otherArray, true); - - if ($i !== false) { - // remove from other array in order to check for duplicate matches - unset($otherArray[$i]); - - $vertices[$vid] = $vertex; - } - } - - return new static($vertices); - } - - /** - * get first vertex (optionally ordered by given criterium $by) from given array of vertices - * - * @param string|callable(Vertex):number $orderBy criterium to sort by. see vertex attribute names custom callback - * @param bool $desc whether to return biggest (true) instead of smallest (default:false) - * @return Vertex - * @throws \UnderflowException if no vertices exist - * @see self::getVerticesOrder() - */ - public function getVertexOrder($orderBy, $desc=false) - { - if (!$this->vertices) { - throw new \UnderflowException('No vertex found'); - } - - $callback = $this->getCallback($orderBy); - - $ret = NULL; - $best = NULL; - foreach ($this->vertices as $vertex) { - $now = $callback($vertex); - - if ($ret === NULL || ($desc && $now > $best) || (!$desc && $now < $best)) { - $ret = $vertex; - $best = $now; - } - } - - return $ret; - } - - /** - * return self reference to Set of Vertices - * - * @return Vertices - */ - public function getVertices() - { - return $this; - } - - /** - * get a new set of Vertices where each Vertex is distinct/unique - * - * Vertex index/keys will be preserved from original array. - * - * @return Vertices - * @uses self::getMap() - */ - public function getVerticesDistinct() - { - $vertices = array(); - foreach ($this->vertices as $vid => $vertex) { - // filter duplicate vertices - if (!\in_array($vertex, $vertices, true)) { - $vertices[$vid] = $vertex; - } - } - - return new self($vertices); - } - - /** - * return array of Vertex instances - * - * @return Vertex[] - */ - public function getVector() - { - return \array_values($this->vertices); - } - - /** - * count number of vertices - * - * @return int - * @see self::isEmpty() - */ - public function count() - { - return \count($this->vertices); - } - - /** - * check whether this Set of Vertices is empty - * - * A Set if empty if no single Vertex instance is added. This is faster - * than calling `count() === 0`. - * - * @return bool - */ - public function isEmpty() - { - return !$this->vertices; - } - - /** - * check whether this set contains any duplicate vertex instances - * - * @return bool - * @uses self::getMap() - */ - public function hasDuplicates() - { - $found = array(); - foreach ($this->vertices as $vertex) { - if (\in_array($vertex, $found, true)) { - return true; - } - - $found[] = $vertex; - } - - return false; - } - - /** - * get Iterator - * - * This method implements the IteratorAggregate interface and allows this - * Set of Vertices to be used in foreach loops. - * - * @return \IteratorIterator - */ - public function getIterator() - { - return new \IteratorIterator(new \ArrayIterator($this->vertices)); - } - - /** - * call given $callback on each Vertex and sum their results - * - * @param string|callable(Vertex):number $callback callback to sum by. See vertex attribute names or custom callback - * @return number - * @uses self::getCallback() - */ - public function getSumCallback($callback) - { - $callback = $this->getCallback($callback); - - $sum = 0; - foreach ($this->vertices as $vertex) { - $sum += $callback($vertex); - } - return $sum; - } - - private function getVertexMatchOrNull($callbackCheck) - { - $callbackCheck = $this->getCallback($callbackCheck); - - foreach ($this->vertices as $vertex) { - if ($callbackCheck($vertex)) { - return $vertex; - } - } - return null; - } - - /** - * get callback/Closure to be called on Vertex instances for given callback identifier - * - * @param string|callable(Vertex):number $callback - * @return callable(Vertex):number - */ - private function getCallback($callback) - { - if (\is_callable($callback)) { - if (\is_array($callback)) { - $callback = function (Vertex $vertex) use ($callback) { - return \call_user_func($callback, $vertex); - }; - } - return $callback; - } - - return function (Vertex $vertex) use ($callback) { - return $vertex->getAttribute($callback); - }; - } -} diff --git a/src/Set/VerticesAggregate.php b/src/Set/VerticesAggregate.php deleted file mode 100644 index 1bc9865e..00000000 --- a/src/Set/VerticesAggregate.php +++ /dev/null @@ -1,14 +0,0 @@ -edges as $edge) { + if ($edge->isConnection($this, $vertex)) { + return true; + } + } - return $this->getEdges()->hasEdgeMatch(function (Edge $edge) use ($that, $vertex) { - return $edge->isConnection($that, $vertex); - }); + return false; } /** @@ -85,26 +83,28 @@ public function hasEdgeFrom(Vertex $vertex) } /** - * get set of ALL Edges attached to this vertex + * get list of ALL edges attached to this vertex * - * @return Edges + * @psalm-return list + * @return Edge[] */ public function getEdges() { - return new Edges($this->edges); + return $this->edges; } /** - * get set of all outgoing Edges attached to this vertex + * get list of all outgoing edges attached to this vertex * - * @return Edges + * @psalm-return list + * @return Edge[] */ public function getEdgesOut() { $that = $this; $prev = null; - return $this->getEdges()->getEdgesMatch(function (Edge $edge) use ($that, &$prev) { + return \array_values(\array_filter($this->edges, function (Edge $edge) use ($that, &$prev) { $ret = $edge->hasVertexStart($that); // skip duplicate directed loop edges @@ -114,20 +114,21 @@ public function getEdgesOut() $prev = $edge; return $ret; - }); + })); } /** - * get set of all ingoing Edges attached to this vertex + * get list of all ingoing edges attached to this vertex * - * @return Edges + * @psalm-return list + * @return Edge[] */ public function getEdgesIn() { $that = $this; $prev = null; - return $this->getEdges()->getEdgesMatch(function (Edge $edge) use ($that, &$prev) { + return \array_values(\array_filter($this->edges, function (Edge $edge) use ($that, &$prev) { $ret = $edge->hasVertexTarget($that); // skip duplicate directed loop edges @@ -137,30 +138,32 @@ public function getEdgesIn() $prev = $edge; return $ret; - }); + })); } /** - * get set of Edges FROM this vertex TO the given vertex + * get list of edges FROM this vertex TO the given vertex * * @param Vertex $vertex - * @return Edges + * @psalm-return list + * @return Edge[] * @uses Edge::hasVertexTarget() */ public function getEdgesTo(Vertex $vertex) { $that = $this; - return $this->getEdges()->getEdgesMatch(function (Edge $edge) use ($that, $vertex) { + return \array_values(\array_filter($this->edges, function (Edge $edge) use ($that, $vertex) { return $edge->isConnection($that, $vertex); - }); + })); } /** - * get set of Edges FROM the given vertex TO this vertex + * get list of edges FROM the given vertex TO this vertex * * @param Vertex $vertex - * @return Edges + * @psalm-return list + * @return Edge[] * @uses Vertex::getEdgesTo() */ public function getEdgesFrom(Vertex $vertex) @@ -169,13 +172,13 @@ public function getEdgesFrom(Vertex $vertex) } /** - * get set of adjacent Vertices of this vertex (edge FROM or TO this vertex) + * get list of adjacent vertices of this vertex (edge FROM or TO this vertex) * * If there are multiple parallel edges between the same Vertex, it will be - * returned several times in the resulting Set of Vertices. If you only - * want unique Vertex instances, use `getVerticesDistinct()`. + * returned several times in the resulting list of vertices. * - * @return Vertices + * @psalm-return list + * @return Vertex[] * @uses Edge::hasVertexStart() * @uses Edge::getVerticesToFrom() * @uses Edge::getVerticesFromTo() @@ -191,17 +194,17 @@ public function getVerticesEdge() } } - return new Vertices($ret); + return $ret; } /** - * get set of all Vertices this vertex has an edge to + * get list of all vertices this vertex has an edge to * * If there are multiple parallel edges to the same Vertex, it will be - * returned several times in the resulting Set of Vertices. If you only - * want unique Vertex instances, use `getVerticesDistinct()`. + * returned several times in the resulting list of vertices. * - * @return Vertices + * @psalm-return list + * @return Vertex[] * @uses Vertex::getEdgesOut() * @uses Edge::getVerticesToFrom() */ @@ -212,17 +215,17 @@ public function getVerticesEdgeTo() $ret []= $edge->getVertexToFrom($this); } - return new Vertices($ret); + return $ret; } /** - * get set of all Vertices that have an edge TO this vertex + * get list of all vertices that have an edge TO this vertex * * If there are multiple parallel edges from the same Vertex, it will be - * returned several times in the resulting Set of Vertices. If you only - * want unique Vertex instances, use `getVerticesDistinct()`. + * returned several times in the resulting list of vertices. * - * @return Vertices + * @psalm-return list + * @return Vertex[] * @uses Vertex::getEdgesIn() * @uses Edge::getVerticesFromTo() */ @@ -233,7 +236,7 @@ public function getVerticesEdgeFrom() $ret []= $edge->getVertexFromTo($this); } - return new Vertices($ret); + return $ret; } /** diff --git a/src/Walk.php b/src/Walk.php index b26beb86..ebd7ecf9 100644 --- a/src/Walk.php +++ b/src/Walk.php @@ -2,10 +2,6 @@ namespace Graphp\Graph; -use Graphp\Graph\Set\Edges; -use Graphp\Graph\Set\Vertices; -use Graphp\Graph\Set\DualAggregate; - /** * Base Walk class * @@ -16,16 +12,16 @@ * @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 +class Walk { /** * construct new walk from given start vertex and given array of edges * - * @param Edges $edges + * @param Edge[] $edges * @param Vertex $startVertex * @return Walk */ - public static function factoryFromEdges(Edges $edges, Vertex $startVertex) + public static function factoryFromEdges(array $edges, Vertex $startVertex) { $vertices = array($startVertex); $vertexCurrent = $startVertex; @@ -34,20 +30,20 @@ public static function factoryFromEdges(Edges $edges, Vertex $startVertex) $vertices []= $vertexCurrent; } - return new self(new Vertices($vertices), $edges); + return new self($vertices, \array_values($edges)); } /** - * create new walk instance between given set of Vertices / array of Vertex instances + * create new walk instance between given array of Vertex instances * - * @param Vertices $vertices + * @param Vertex[] $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 + * @see self::factoryCycleFromVertices() for parameters $orderBy and $desc */ - public static function factoryFromVertices(Vertices $vertices, $orderBy = null, $desc = false) + public static function factoryFromVertices(array $vertices, $orderBy = null, $desc = false) { $edges = array(); $last = NULL; @@ -55,12 +51,8 @@ public static function factoryFromVertices(Vertices $vertices, $orderBy = null, // 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); - } + \assert($last instanceof Vertex); + $edges[] = self::pickEdge($last->getEdgesTo($vertex), $orderBy, $desc); } $last = $vertex; } @@ -68,30 +60,30 @@ public static function factoryFromVertices(Vertices $vertices, $orderBy = null, throw new \UnderflowException('No vertices given'); } - return new self($vertices, new Edges($edges)); + return new self(\array_values($vertices), $edges); } /** * create new cycle instance with edges between given vertices * - * @param Vertices $vertices + * @param Vertex[] $vertices * @param null|string|callable(Edge):number $orderBy * @param bool $desc * @return Walk * @throws \UnderflowException if no vertices were given * @throws \InvalidArgumentException if vertices do not form a valid cycle - * @see Edges::getEdgeOrder() for parameters $by and $desc + * @see self::factoryCycleFromVertices() for parameters $orderBy and $desc * @uses self::factoryFromVertices() */ - public static function factoryCycleFromVertices(Vertices $vertices, $orderBy = null, $desc = false) + public static function factoryCycleFromVertices(array $vertices, $orderBy = null, $desc = false) { $cycle = self::factoryFromVertices($vertices, $orderBy, $desc); - if ($cycle->getEdges()->isEmpty()) { + if (!$cycle->getEdges()) { throw new \InvalidArgumentException('Cycle with no edges can not exist'); } - if ($cycle->getVertices()->getVertexFirst() !== $cycle->getVertices()->getVertexLast()) { + if (\reset($vertices) !== \end($vertices)) { throw new \InvalidArgumentException('Cycle has to start and end at the same vertex'); } @@ -101,18 +93,19 @@ public static function factoryCycleFromVertices(Vertices $vertices, $orderBy = n /** * create new cycle instance with vertices connected by given edges * - * @param Edges $edges + * @param Edge[] $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) + public static function factoryCycleFromEdges(array $edges, Vertex $startVertex) { $cycle = self::factoryFromEdges($edges, $startVertex); // ensure this walk is actually a cycle by checking start = end - if ($cycle->getVertices()->getVertexLast() !== $startVertex) { + $vertices = $cycle->getVertices(); + if (\end($vertices) !== $startVertex) { throw new \InvalidArgumentException('The given array of edges does not represent a cycle'); } @@ -120,16 +113,59 @@ public static function factoryCycleFromEdges(Edges $edges, Vertex $startVertex) } /** - * @var Vertices + * @param Edge[] $edges + * @param null|string|callable(Edge):number $orderBy + * @param bool $desc + * @return Edge + * @throws \UnderflowException + */ + private static function pickEdge(array $edges, $orderBy, $desc) + { + if (!$edges) { + throw new \UnderflowException('No edges between two vertices found'); + } + + if ($orderBy === null) { + return \reset($edges); + } + + if (\is_string($orderBy)) { + $orderBy = function (Edge $edge) use ($orderBy) { + return $edge->getAttribute($orderBy); + }; + } + + $ret = NULL; + $best = NULL; + foreach ($edges as $edge) { + $now = $orderBy($edge); + + if ($ret === NULL || ($desc && $now > $best) || (!$desc && $now < $best)) { + $ret = $edge; + $best = $now; + } + } + + return $ret; + } + + /** + * @var Vertex[] */ protected $vertices; /** - * @var Edges + * @var Edge[] */ protected $edges; - protected function __construct(Vertices $vertices, Edges $edges) + /** + * @psalm-param list $vertices + * @psalm-param list $edges + * @param Vertex[] $vertices + * @param Edge[] $edges + */ + protected function __construct(array $vertices, array $edges) { $this->vertices = $vertices; $this->edges = $edges; @@ -145,16 +181,17 @@ protected function __construct(Vertices $vertices, Edges $edges) */ public function getGraph() { - return $this->vertices->getVertexFirst()->getGraph(); + $vertex = \reset($this->vertices); + \assert($vertex instanceof Vertex); + + return $vertex->getGraph(); } /** - * return set of all Edges of walk (in sequence visited in walk, may contain duplicates) + * return list 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 + * @psalm-return list + * @return Edge[] */ public function getEdges() { @@ -162,18 +199,26 @@ public function getEdges() } /** - * return set of all Vertices of walk (in sequence visited in walk, may contain duplicates) + * return list of all vertices of walk (in sequence visited in walk, may contain duplicates) + * + * If you need to return the source vertex (first vertex of walk), you can + * use something like this: * - * If you need to return set a of all unique Vertices of walk, use - * `Walk::getVertices()->getVerticesDistinct()` instead. + * ```php + * $vertices = $walk->getVertices(); + * $firstVertex = \reset($vertices); + * ``` * - * 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), + * you can use something like this: * - * If you need to return the target/destination vertex (last vertex of walk), use - * `Walk::getVertices()->getVertexLast()` instead. + * ```php + * $vertices = $walk->getVertices(); + * $lastVertex = \end($vertices); + * ``` * - * @return Vertices + * @psalm-return list + * @return Vertex[] */ public function getVertices() { @@ -183,19 +228,17 @@ public function getVertices() /** * get alternating sequence of vertex, edge, vertex, edge, ..., vertex * - * @return array + * @psalm-return list + * @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 []= $this->vertices[$i]; + $ret []= $this->edges[$i]; } - $ret[] = $vertices[$i]; + $ret[] = $this->vertices[$i]; return $ret; } diff --git a/tests/EdgeDirectedTest.php b/tests/EdgeDirectedTest.php index 062e808f..7ffffc37 100644 --- a/tests/EdgeDirectedTest.php +++ b/tests/EdgeDirectedTest.php @@ -20,7 +20,7 @@ protected function createEdgeLoop() public function testVerticesEnds() { - $this->assertEquals(array($this->v1), $this->edge->getVerticesStart()->getVector()); - $this->assertEquals(array($this->v2), $this->edge->getVerticesTarget()->getVector()); + $this->assertEquals(array($this->v1), $this->edge->getVerticesStart()); + $this->assertEquals(array($this->v2), $this->edge->getVerticesTarget()); } } diff --git a/tests/EdgeTest.php b/tests/EdgeTest.php index 96de75ec..a49f47f4 100644 --- a/tests/EdgeTest.php +++ b/tests/EdgeTest.php @@ -63,7 +63,7 @@ public function testEdgeConstructorWithAttributeReturnsAttributes() public function testEdgeVertices() { - $this->assertEquals(array($this->v1, $this->v2), $this->edge->getVertices()->getVector()); + $this->assertEquals(array($this->v1, $this->v2), $this->edge->getVertices()); $this->assertSame($this->graph, $this->edge->getGraph()); } @@ -100,7 +100,7 @@ public function testLoop() $edge = $this->createEdgeLoop(); $this->assertTrue($edge->isLoop()); - $this->assertEquals(array($this->v1, $this->v1), $edge->getVertices()->getVector()); + $this->assertEquals(array($this->v1, $this->v1), $edge->getVertices()); $this->assertSame($this->v1, $edge->getVertexFromTo($this->v1)); $this->assertSame($this->v1, $edge->getVertexToFrom($this->v1)); } diff --git a/tests/EdgeUndirectedTest.php b/tests/EdgeUndirectedTest.php index efbc0e4a..3ad72c2e 100644 --- a/tests/EdgeUndirectedTest.php +++ b/tests/EdgeUndirectedTest.php @@ -20,7 +20,7 @@ protected function createEdgeLoop() public function testVerticesEnds() { - $this->assertEquals(array($this->v1, $this->v2), $this->edge->getVerticesStart()->getVector()); - $this->assertEquals(array($this->v2, $this->v1), $this->edge->getVerticesTarget()->getVector()); + $this->assertEquals(array($this->v1, $this->v2), $this->edge->getVerticesStart()); + $this->assertEquals(array($this->v2, $this->v1), $this->edge->getVerticesTarget()); } } diff --git a/tests/GraphTest.php b/tests/GraphTest.php index 28aee82a..9a25a245 100644 --- a/tests/GraphTest.php +++ b/tests/GraphTest.php @@ -3,8 +3,6 @@ namespace Graphp\Graph\Tests; use Graphp\Graph\Graph; -use Graphp\Graph\Set\Edges; -use Graphp\Graph\Set\Vertices; class GraphTest extends EntityTest { @@ -67,7 +65,7 @@ public function testCreateMultigraph() $this->assertEquals(2, count($graph->getEdges())); $this->assertEquals(2, count($v1->getEdges())); - $this->assertEquals(array($v2, $v2), $v1->getVerticesEdge()->getVector()); + $this->assertEquals(array($v2, $v2), $v1->getVerticesEdge()); } public function testCreateMixedGraph() @@ -87,8 +85,8 @@ public function testCreateMixedGraph() $this->assertEquals(2, count($v2->getEdgesOut())); $this->assertEquals(1, count($v2->getEdgesIn())); - $this->assertEquals(array($v1, $v3), $v2->getVerticesEdgeTo()->getVector()); - $this->assertEquals(array($v1), $v2->getVerticesEdgeFrom()->getVector()); + $this->assertEquals(array($v1, $v3), $v2->getVerticesEdgeTo()); + $this->assertEquals(array($v1), $v2->getVerticesEdgeFrom()); } public function testWithoutEdgeReturnsNewGraphAndDoesNotModifyOriginal() @@ -99,13 +97,13 @@ public function testWithoutEdgeReturnsNewGraphAndDoesNotModifyOriginal() $v2 = $graph->createVertex(); $edge = $graph->createEdgeUndirected($v1, $v2); - $this->assertEquals(array($edge), $graph->getEdges()->getVector()); + $this->assertEquals(array($edge), $graph->getEdges()); $new = $graph->withoutEdge($edge); $this->assertInstanceOf(get_class($graph), $new); - $this->assertEquals(array(), $new->getEdges()->getVector()); - $this->assertEquals(array($edge), $graph->getEdges()->getVector()); + $this->assertEquals(array(), $new->getEdges()); + $this->assertEquals(array($edge), $graph->getEdges()); } public function testWithoutEdgesSameTwiceReturnsNewGraphAndDoesNotModifyOriginal() @@ -116,13 +114,13 @@ public function testWithoutEdgesSameTwiceReturnsNewGraphAndDoesNotModifyOriginal $v2 = $graph->createVertex(); $edge = $graph->createEdgeUndirected($v1, $v2); - $this->assertEquals(array($edge), $graph->getEdges()->getVector()); + $this->assertEquals(array($edge), $graph->getEdges()); - $new = $graph->withoutEdges(new Edges(array($edge, $edge))); + $new = $graph->withoutEdges(array($edge, $edge)); $this->assertInstanceOf(get_class($graph), $new); - $this->assertEquals(array(), $new->getEdges()->getVector()); - $this->assertEquals(array($edge), $graph->getEdges()->getVector()); + $this->assertEquals(array(), $new->getEdges()); + $this->assertEquals(array($edge), $graph->getEdges()); } public function testWithoutEdgeFromOtherGraphReturnsSameGraphWithoutModification() @@ -134,12 +132,31 @@ public function testWithoutEdgeFromOtherGraphReturnsSameGraphWithoutModification $graph->createEdgeUndirected($v1, $v2); $clone = clone $graph; - $edge = $clone->getEdges()->getEdgeFirst(); + $edges = $clone->getEdges(); + $edge = reset($edges); $new = $graph->withoutEdge($edge); $this->assertSame($new, $graph); - $this->assertEquals(array($edge), $graph->getEdges()->getVector()); + $this->assertEquals(array($edge), $graph->getEdges()); + } + + public function testWithoutEdgeParallelReturnsNewGraphWithSingleEdge() + { + // /---\ + // 1 2 + // \---/ + $graph = new Graph(); + $v1 = $graph->createVertex(); + $v2 = $graph->createVertex(); + $e1 = $graph->createEdgeUndirected($v1, $v2); + $graph->createEdgeUndirected($v1, $v2); + + $new = $graph->withoutEdge($e1); + + $this->assertInstanceOf(get_class($graph), $new); + $this->assertCount(1, $new->getEdges()); + $this->assertEquals(array_values($new->getEdges()), $new->getEdges()); } public function testWithoutVertexReturnsNewGraphAndDoesNotModifyOriginal() @@ -147,13 +164,13 @@ public function testWithoutVertexReturnsNewGraphAndDoesNotModifyOriginal() $graph = new Graph(); $vertex = $graph->createVertex(); - $this->assertEquals(array($vertex), $graph->getVertices()->getVector()); + $this->assertEquals(array($vertex), $graph->getVertices()); $new = $graph->withoutVertex($vertex); $this->assertInstanceOf(get_class($graph), $new); - $this->assertEquals(array(), $new->getVertices()->getVector()); - $this->assertEquals(array($vertex), $graph->getVertices()->getVector()); + $this->assertEquals(array(), $new->getVertices()); + $this->assertEquals(array($vertex), $graph->getVertices()); } public function testWithoutVerticesTwiceReturnsNewGraphAndDoesNotModifyOriginal() @@ -161,13 +178,13 @@ public function testWithoutVerticesTwiceReturnsNewGraphAndDoesNotModifyOriginal( $graph = new Graph(); $vertex = $graph->createVertex(); - $this->assertEquals(array($vertex), $graph->getVertices()->getVector()); + $this->assertEquals(array($vertex), $graph->getVertices()); - $new = $graph->withoutVertices(new Vertices(array($vertex, $vertex))); + $new = $graph->withoutVertices(array($vertex, $vertex)); $this->assertInstanceOf(get_class($graph), $new); - $this->assertEquals(array(), $new->getVertices()->getVector()); - $this->assertEquals(array($vertex), $graph->getVertices()->getVector()); + $this->assertEquals(array(), $new->getVertices()); + $this->assertEquals(array($vertex), $graph->getVertices()); } public function testWithoutVertexFromOtherGraphReturnsSameGraphWithoutModification() @@ -181,7 +198,7 @@ public function testWithoutVertexFromOtherGraphReturnsSameGraphWithoutModificati $new = $graph->withoutVertex($vertex); $this->assertSame($new, $graph); - $this->assertEquals(array($vertex), $graph->getVertices()->getVector()); + $this->assertEquals(array($vertex), $graph->getVertices()); } public function testWithoutVertexRemovesAttachedUndirectedEdge() @@ -230,6 +247,8 @@ public function testWithoutVertexWithUndirectedLoopReturnsRemainingGraph() $this->assertCount(2, $new->getVertices()); $this->assertCount(1, $new->getEdges()); + + $this->assertEquals(array_values($new->getVertices()), $new->getVertices()); } public function testWithoutVertexWithDirectedLoopReturnsEmptyGraph() @@ -247,6 +266,19 @@ public function testWithoutVertexWithDirectedLoopReturnsEmptyGraph() $this->assertCount(0, $new->getEdges()); } + public function testWithoutVertexUnconnectedReturnsNewGraphWithSingleVertex() + { + // 1, 2 + $graph = new Graph(); + $v1 = $graph->createVertex(); + $graph->createVertex(); + + $new = $graph->withoutVertex($v1); + + $this->assertCount(1, $new->getVertices()); + $this->assertEquals(array_values($new->getVertices()), $new->getVertices()); + } + public function testGraphCloneEmptyGraph() { $graph = new Graph(); diff --git a/tests/Set/EdgesTest.php b/tests/Set/EdgesTest.php deleted file mode 100644 index ed62a371..00000000 --- a/tests/Set/EdgesTest.php +++ /dev/null @@ -1,313 +0,0 @@ -createEdges(array()); - - $this->assertEquals(0, $edges->count()); - $this->assertEquals(0, count($edges)); - $this->assertEquals(array(), $edges->getVector()); - $this->assertTrue($edges->isEmpty()); - $this->assertTrue($edges->getEdges()->isEmpty()); - $this->assertTrue($edges->getEdgesOrder(function (Edge $edge) { - return $edge->getAttribute('weight'); - })->isEmpty()); - $this->assertTrue($edges->getEdgesOrder('weight')->isEmpty()); - $this->assertTrue($edges->getEdgesDistinct()->isEmpty()); - $this->assertTrue($edges->getEdgesMatch(function() { })->isEmpty()); - - return $edges; - } - - /** - * @param Edges $edges - * @depends testEmpty - */ - public function testEmptyDoesNotHaveFirst(Edges $edges) - { - $this->setExpectedException('UnderflowException'); - $edges->getEdgeFirst(); - } - - /** - * @param Edges $edges - * @depends testEmpty - */ - public function testEmptyDoesNotHaveLast(Edges $edges) - { - $this->setExpectedException('UnderflowException'); - $edges->getEdgeLast(); - } - - /** - * @param Edges $edges - * @depends testEmpty - */ - public function testEmptyDoesNotHaveRandom(Edges $edges) - { - $this->setExpectedException('UnderflowException'); - $edges->getEdgeRandom(); - } - - /** - * @param Edges $edges - * @depends testEmpty - */ - public function testEmptyDoesNotHaveOrdered(Edges $edges) - { - $this->setExpectedException('UnderflowException'); - $edges->getEdgeOrder('weight'); - } - - public function testTwo() - { - // 1 -- 2 -- 3 - $graph = new Graph(); - $v1 = $graph->createVertex(); - $v2 = $graph->createVertex(); - $v3 = $graph->createVertex(); - $e1 = $graph->createEdgeUndirected($v1, $v2); - $e2 = $graph->createEdgeUndirected($v2, $v3); - - $edges = $this->createEdges(array($e1, $e2)); - - $this->assertEquals(2, count($edges)); - - $this->assertSame($e1, $edges->getEdgeFirst()); - $this->assertSame($e1, $edges->getEdgeIndex(0)); - - $this->assertSame($e2, $edges->getEdgeLast()); - $this->assertSame($e2, $edges->getEdgeIndex(1)); - - $this->assertEquals(0, $edges->getIndexEdge($e1)); - - return $edges; - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoDoesNotContainIndex3(Edges $edges) - { - $this->setExpectedException('OutOfBoundsException'); - $edges->getEdgeIndex(3); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoDoesNotContainEdge3(Edges $edges) - { - $graph = new Graph(); - $v3 = $graph->createVertex(); - $e3 = $graph->createEdgeUndirected($v3, $v3); - - $this->setExpectedException('OutOfBoundsException'); - $edges->getIndexEdge($e3); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoAsMap(Edges $edges) - { - $distinct = $edges->getEdgesDistinct(); - - $this->assertInstanceOf('Graphp\Graph\Set\Edges', $distinct); - $this->assertEquals(2, count($distinct)); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoRandom(Edges $edges) - { - $edgeRandom = $edges->getEdgeRandom(); - - $this->assertInstanceOf('Graphp\Graph\Edge', $edgeRandom); - $edges->getEdgeIndex($edges->getIndexEdge($edgeRandom)); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoShuffled(Edges $edges) - { - $edgesRandom = $edges->getEdgesShuffled(); - - $this->assertInstanceOf('Graphp\Graph\Set\Edges', $edgesRandom); - $this->assertEquals(2, count($edgesRandom)); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoIterator(Edges $edges) - { - $this->assertInstanceOf('Iterator', $edges->getIterator()); - - $values = array_values(iterator_to_array($edges)); - $this->assertEquals($edges->getVector(), $values); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoMatch(Edges $edges) - { - $edgesMatch = $edges->getEdgesMatch(array($this, 'returnTrue')); - $this->assertEquals($edges->getVector(), $edgesMatch->getVector()); - - $edgeMatch = $edges->getEdgeMatch(array($this, 'returnTrue')); - $this->assertEquals($edges->getEdgeFirst(), $edgeMatch); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoMatchEmpty(Edges $edges) - { - $edgesMatch = $edges->getEdgesMatch(array($this, 'returnFalse')); - $this->assertCount(0, $edgesMatch); - } - - /** - * @param Edges $edges - * @depends testTwo - */ - public function testTwoMatchFail(Edges $edges) - { - $this->setExpectedException('UnderflowException'); - $edges->getEdgeMatch(array($this, 'returnFalse')); - } - - public function returnTrue(Edge $edge) - { - return true; - } - - public function returnFalse(Edge $edge) - { - return false; - } - - public function testOrderByGroup() - { - $graph = new Graph(); - $v1 = $graph->createVertex(); - $v2 = $graph->createVertex(); - $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 1); - $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 100); - $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 5); - $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 100); - $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 100); - $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 2); - $biggest = $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 200); - - $edges = $graph->getEdges(); - $edgesOrdered = $edges->getEdgesOrder(function (Edge $edge) { - return $edge->getAttribute('weight'); - }); - - $this->assertInstanceOf('Graphp\Graph\Set\Edges', $edgesOrdered); - $this->assertEquals(1, $edgesOrdered->getEdgeFirst()->getAttribute('weight')); - $this->assertEquals(200, $edgesOrdered->getEdgeLast()->getAttribute('weight')); - - $this->assertSame($biggest, $edgesOrdered->getEdgeLast()); - $this->assertSame($biggest, $edges->getEdgeOrder(function (Edge $edge) { - return $edge->getAttribute('weight'); - }, true)); - - $sumweights = function(Edge $edge) { - return $edge->getAttribute('weight'); - }; - $this->assertSame(508, $edges->getSumCallback($sumweights)); - $this->assertSame(508, $edgesOrdered->getSumCallback($sumweights)); - } - - public function testOrderByAttribute() - { - $graph = new Graph(); - $v1 = $graph->createVertex(); - $v2 = $graph->createVertex(); - $e1 = $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 20); - $e2 = $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 10); - - $edges = $graph->getEdges()->getEdgesOrder('weight'); - - $this->assertInstanceOf('Graphp\Graph\Set\Edges', $edges); - $this->assertSame($e2, $edges->getEdgeFirst()); - $this->assertSame($e1, $edges->getEdgeLast()); - - $this->assertSame($e1, $edges->getEdgeOrder('weight', true)); - - $this->assertSame(30, $graph->getEdges()->getSumCallback('weight')); - $this->assertSame(30, $edges->getSumCallback('weight')); - } - - public function testIntersection() - { - $graph = new Graph(); - $v1 = $graph->createVertex(); - $v2 = $graph->createVertex(); - $e1 = $graph->createEdgeUndirected($v1, $v2); - $e2 = $graph->createEdgeUndirected($v1, $v2); - $e3 = $graph->createEdgeUndirected($v1, $v2); - - $edges1 = $this->createEdges(array($e1, $e2)); - $edges2 = $this->createEdges(array($e2, $e3)); - - $edges3 = $edges1->getEdgesIntersection($edges2); - $this->assertCount(1, $edges3); - $this->assertEquals($e2, $edges3->getEdgeFirst()); - } - - public function testIntersectionDuplicates() - { - $graph = new Graph(); - $v1 = $graph->createVertex(); - $v2 = $graph->createVertex(); - $e1 = $graph->createEdgeUndirected($v1, $v2); - - $edges1 = $this->createEdges(array($e1, $e1, $e1)); - $edges2 = $this->createEdges(array($e1, $e1)); - - $edges3 = $edges1->getEdgesIntersection($edges2); - $this->assertCount(2, $edges3); - } - - public function testIntersectionEmpty() - { - $edges1 = new Edges(); - $edges2 = new Edges(); - - $edges3 = $edges1->getEdgesIntersection($edges2); - $this->assertCount(0, $edges3); - } -} diff --git a/tests/Set/VerticesTest.php b/tests/Set/VerticesTest.php deleted file mode 100644 index 8ce38059..00000000 --- a/tests/Set/VerticesTest.php +++ /dev/null @@ -1,303 +0,0 @@ -createVertices(array()); - - $this->assertEquals(0, $vertices->count()); - $this->assertEquals(0, count($vertices)); - $this->assertEquals(array(), $vertices->getVector()); - $this->assertTrue($vertices->isEmpty()); - $this->assertTrue($vertices->getVertices()->isEmpty()); - $this->assertTrue($vertices->getVerticesOrder(function (Vertex $vertex) { - return $vertex->getAttribute('id'); - })->isEmpty()); - $this->assertTrue($vertices->getVerticesOrder('id')->isEmpty()); - $this->assertTrue($vertices->getVerticesDistinct()->isEmpty()); - $this->assertTrue($vertices->getVerticesMatch(function() { })->isEmpty()); - $this->assertFalse($vertices->hasDuplicates()); - - return $vertices; - } - - /** - * @param Vertices $vertices - * @depends testEmpty - */ - public function testEmptyDoesNotHaveFirst(Vertices $vertices) - { - $this->setExpectedException('UnderflowException'); - $vertices->getVertexFirst(); - } - - /** - * @param Vertices $vertices - * @depends testEmpty - */ - public function testEmptyDoesNotHaveLast(Vertices $vertices) - { - $this->setExpectedException('UnderflowException'); - $vertices->getVertexLast(); - } - - /** - * @param Vertices $vertices - * @depends testEmpty - */ - public function testEmptyDoesNotHaveRandom(Vertices $vertices) - { - $this->setExpectedException('UnderflowException'); - $vertices->getVertexRandom(); - } - - /** - * @param Vertices $vertices - * @depends testEmpty - */ - public function testEmptyDoesNotHaveMatching(Vertices $vertices) - { - $this->assertFalse($vertices->hasVertexMatch(function () { return true; })); - } - - /** - * @param Vertices $vertices - * @depends testEmpty - */ - public function testGetVertexMatchOneEmptyThrowsUnderflowException(Vertices $vertices) - { - $this->setExpectedException('UnderflowException'); - $vertices->getVertexMatch(function () { return true; }); - } - - /** - * @param Vertices $vertices - * @depends testEmpty - */ - public function testEmptyDoesNotHaveOrdered(Vertices $vertices) - { - $this->setExpectedException('UnderflowException'); - $vertices->getVertexOrder('group'); - } - - public function testTwo() - { - $graph = new Graph(); - $v1 = $graph->createVertex(); - $v2 = $graph->createVertex(); - - $vertices = $this->createVertices(array(1 => $v1, 2 => $v2)); - $this->assertEquals(2, count($vertices)); - - $this->assertSame($v1, $vertices->getVertexFirst()); - - $this->assertSame($v2, $vertices->getVertexLast()); - - $this->assertEquals(1, $vertices->getIndexVertex($v1)); - - return $vertices; - } - - /** - * @param Vertices $vertices - * @depends testTwo - */ - public function testTwoDoesNotContainVertex3(Vertices $vertices) - { - $graph = new Graph(); - $v3 = $graph->createVertex(); - - $this->setExpectedException('OutOfBoundsException'); - $vertices->getIndexVertex($v3); - } - - /** - * @param Vertices $vertices - * @depends testTwo - */ - public function testTwoAsMap(Vertices $vertices) - { - $distinct = $vertices->getVerticesDistinct(); - - $this->assertInstanceOf('Graphp\Graph\Set\Vertices', $distinct); - $this->assertEquals(2, count($distinct)); - } - - /** - * @param Vertices $vertices - * @depends testTwo - */ - public function testTwoRandom(Vertices $vertices) - { - $vertexRandom = $vertices->getVertexRandom(); - - $this->assertInstanceOf('Graphp\Graph\Vertex', $vertexRandom); - $vertices->getIndexVertex($vertexRandom); - } - - /** - * @param Vertices $vertices - * @depends testTwo - */ - public function testTwoShuffled(Vertices $vertices) - { - $verticesRandom = $vertices->getVerticesShuffled(); - - $this->assertInstanceOf('Graphp\Graph\Set\Vertices', $verticesRandom); - $this->assertEquals(2, count($verticesRandom)); - } - - /** - * @param Vertices $vertices - * @depends testTwo - */ - public function testTwoIterator(Vertices $vertices) - { - $this->assertInstanceOf('Iterator', $vertices->getIterator()); - - $values = array_values(iterator_to_array($vertices)); - $this->assertEquals($vertices->getVector(), $values); - } - - /** - * @param Vertices $vertices - * @depends testTwo - */ - public function testTwoMatch(Vertices $vertices) - { - $verticesMatch = $vertices->getVerticesMatch(array($this, 'returnTrue')); - $this->assertEquals($vertices->getVector(), $verticesMatch->getVector()); - - $vertexMatch = $vertices->getVertexMatch(array($this, 'returnTrue')); - $this->assertEquals($vertices->getVertexFirst(), $vertexMatch); - } - - public function returnTrue(Vertex $vertex) - { - return true; - } - - public function testOrderByGroup() - { - $graph = new Graph(); - $graph->createVertex()->setAttribute('group', 1); - $graph->createVertex()->setAttribute('group', 100); - $graph->createVertex()->setAttribute('group', 5); - $graph->createVertex()->setAttribute('group', 100); - $graph->createVertex()->setAttribute('group', 100); - $graph->createVertex()->setAttribute('group', 2); - $biggest = $graph->createVertex()->setAttribute('group', 200); - - $vertices = $graph->getVertices(); - $verticesOrdered = $vertices->getVerticesOrder('group'); - - $this->assertInstanceOf('Graphp\Graph\Set\Vertices', $verticesOrdered); - $this->assertEquals(1, $verticesOrdered->getVertexFirst()->getAttribute('group')); - $this->assertEquals(200, $verticesOrdered->getVertexLast()->getAttribute('group')); - - $this->assertSame($biggest, $verticesOrdered->getVertexLast()); - $this->assertSame($biggest, $vertices->getVertexOrder(function (Vertex $vertex) { - return $vertex->getAttribute('group'); - }, true)); - $this->assertSame($biggest, $vertices->getVertexOrder('group', true)); - - $sumgroups = function(Vertex $vertex) { - return $vertex->getAttribute('group'); - }; - $this->assertSame(508, $vertices->getSumCallback($sumgroups)); - $this->assertSame(508, $verticesOrdered->getSumCallback($sumgroups)); - } - - public function testOrderByAttribute() - { - $graph = new Graph(); - $v1 = $graph->createVertex()->setAttribute('votes', 20); - $v2 = $graph->createVertex()->setAttribute('votes', 10); - - $vertices = $graph->getVertices()->getVerticesOrder('votes'); - - $this->assertInstanceOf('Graphp\Graph\Set\Vertices', $vertices); - $this->assertSame($v2, $vertices->getVertexFirst()); - $this->assertSame($v1, $vertices->getVertexLast()); - - $this->assertSame($v1, $vertices->getVertexOrder('votes', true)); - } - - /** - * @param Vertices $vertices - * @depends testEmpty - */ - public function testEmptyIntersectionSelf(Vertices $vertices) - { - $verticesIntersection = $vertices->getVerticesIntersection($vertices); - $this->assertCount(0, $verticesIntersection); - } - - /** - * @param Vertices $verticesEmpty - * @param Vertices $verticesTwo - * @depends testEmpty - * @depends testTwo - */ - public function testEmptyIntersectionTwo(Vertices $verticesEmpty, Vertices $verticesTwo) - { - $verticesIntersection = $verticesEmpty->getVerticesIntersection($verticesTwo); - $this->assertCount(0, $verticesIntersection); - } - - /** - * @param Vertices $vertices - * @depends testTwo - */ - public function testTwoIntersectionSelf(Vertices $vertices) - { - $verticesIntersection = $vertices->getVerticesIntersection($vertices); - $this->assertCount(2, $verticesIntersection); - $this->assertEquals($vertices->getVector(), $verticesIntersection->getVector()); - } - - /** - * @param Vertices $verticesTwo - * @param Vertices $verticesEmpty - * @depends testTwo - * @depends testEmpty - */ - public function testTwoIntersectionEmpty(Vertices $verticesTwo, Vertices $verticesEmpty) - { - $verticesIntersection = $verticesTwo->getVerticesIntersection($verticesEmpty); - $this->assertCount(0, $verticesIntersection); - } - - public function testDuplicates() - { - $graph = new Graph(); - $v1 = $graph->createVertex(); - - $vertices = $this->createVertices(array($v1, $v1, $v1)); - - $this->assertInstanceOf('Graphp\Graph\Set\Vertices', $vertices); - $this->assertCount(3, $vertices); - $this->assertTrue($vertices->hasDuplicates()); - - $verticesDistinct = $vertices->getVerticesDistinct(); - - $this->assertInstanceOf('Graphp\Graph\Set\Vertices', $verticesDistinct); - $this->assertCount(1, $verticesDistinct); - $this->assertFalse($verticesDistinct->hasDuplicates()); - - $this->assertSame($verticesDistinct->getVector(), $verticesDistinct->getVerticesDistinct()->getVector()); - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php index 1dc1d212..7a62db7b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -76,10 +76,10 @@ private function getEdgeDump(Edge $edge) $vertices = $edge->getGraph()->getVertices(); $ret = get_class($edge) . ' '; if ($edge instanceof EdgeDirected) { - $ret .= $vertices->getIndexVertex($edge->getVertexStart()) . ' -> ' . $vertices->getIndexVertex($edge->getVertexEnd()); + $ret .= array_search($edge->getVertexStart(), $vertices) . ' -> ' . array_search($edge->getVertexEnd(), $vertices); } else { - $foo = $edge->getVertices()->getVector(); - $ret .= $vertices->getIndexVertex($foo[0]) . ' -- ' . $vertices->getIndexVertex($foo[1]); + $foo = $edge->getVertices(); + $ret .= array_search($foo[0], $vertices) . ' -- ' . array_search($foo[1], $vertices); } $ret .= PHP_EOL . 'attributes: ' . json_encode($edge->getAttributes()); diff --git a/tests/VertexTest.php b/tests/VertexTest.php index 1e37565b..4b076335 100644 --- a/tests/VertexTest.php +++ b/tests/VertexTest.php @@ -22,7 +22,7 @@ public function setUpVertex() public function testPrecondition() { $this->assertCount(1, $this->graph->getVertices()); - $this->assertEquals(array($this->vertex), $this->graph->getVertices()->getVector()); + $this->assertEquals(array($this->vertex), $this->graph->getVertices()); } public function testConstructorWithoutAttributesHasNoAttributes() @@ -30,7 +30,7 @@ public function testConstructorWithoutAttributesHasNoAttributes() $v2 = new Vertex($this->graph); $this->assertCount(2, $this->graph->getVertices()); - $this->assertEquals(array($this->vertex, $v2), $this->graph->getVertices()->getVector()); + $this->assertEquals(array($this->vertex, $v2), $this->graph->getVertices()); $this->assertNull($v2->getAttribute('hello')); $this->assertEquals('default', $v2->getAttribute('hello', 'default')); @@ -55,9 +55,9 @@ public function testEdges() $e2 = $this->graph->createEdgeUndirected($this->vertex, $v3); $e3 = $this->graph->createEdgeDirected($v4, $this->vertex); - $this->assertEquals(array($e1, $e2, $e3), $this->vertex->getEdges()->getVector()); - $this->assertEquals(array($e2, $e3), $this->vertex->getEdgesIn()->getVector()); - $this->assertEquals(array($e1, $e2), $this->vertex->getEdgesOut()->getVector()); + $this->assertEquals(array($e1, $e2, $e3), $this->vertex->getEdges()); + $this->assertEquals(array($e2, $e3), $this->vertex->getEdgesIn()); + $this->assertEquals(array($e1, $e2), $this->vertex->getEdgesOut()); $this->assertTrue($this->vertex->hasEdgeTo($v2)); $this->assertTrue($this->vertex->hasEdgeTo($v3)); @@ -67,43 +67,43 @@ public function testEdges() $this->assertTrue($this->vertex->hasEdgeFrom($v3)); $this->assertTrue($this->vertex->hasEdgeFrom($v4)); - $this->assertEquals(array($e1), $this->vertex->getEdgesTo($v2)->getVector()); - $this->assertEquals(array($e2), $this->vertex->getEdgesTo($v3)->getVector()); - $this->assertEquals(array(), $this->vertex->getEdgesTo($v4)->getVector()); + $this->assertEquals(array($e1), $this->vertex->getEdgesTo($v2)); + $this->assertEquals(array($e2), $this->vertex->getEdgesTo($v3)); + $this->assertEquals(array(), $this->vertex->getEdgesTo($v4)); - $this->assertEquals(array(), $this->vertex->getEdgesFrom($v2)->getVector()); - $this->assertEquals(array($e2), $this->vertex->getEdgesTo($v3)->getVector()); - $this->assertEquals(array($e3), $this->vertex->getEdgesFrom($v4)->getVector()); + $this->assertEquals(array(), $this->vertex->getEdgesFrom($v2)); + $this->assertEquals(array($e2), $this->vertex->getEdgesTo($v3)); + $this->assertEquals(array($e3), $this->vertex->getEdgesFrom($v4)); - $this->assertEquals(array($v2, $v3, $v4), $this->vertex->getVerticesEdge()->getVector()); - $this->assertEquals(array($v2, $v3), $this->vertex->getVerticesEdgeTo()->getVector()); - $this->assertEquals(array($v3, $v4), $this->vertex->getVerticesEdgeFrom()->getVector()); + $this->assertEquals(array($v2, $v3, $v4), $this->vertex->getVerticesEdge()); + $this->assertEquals(array($v2, $v3), $this->vertex->getVerticesEdgeTo()); + $this->assertEquals(array($v3, $v4), $this->vertex->getVerticesEdgeFrom()); } public function testUndirectedLoopEdgeReturnsEdgeTwiceInAndOut() { $edge = $this->graph->createEdgeUndirected($this->vertex, $this->vertex); - $this->assertEquals(array($edge, $edge), $this->vertex->getEdges()->getVector()); - $this->assertEquals(array($edge, $edge), $this->vertex->getEdgesIn()->getVector()); - $this->assertEquals(array($edge, $edge), $this->vertex->getEdgesOut()->getVector()); + $this->assertEquals(array($edge, $edge), $this->vertex->getEdges()); + $this->assertEquals(array($edge, $edge), $this->vertex->getEdgesIn()); + $this->assertEquals(array($edge, $edge), $this->vertex->getEdgesOut()); - $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdge()->getVector()); - $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdgeTo()->getVector()); - $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdgeFrom()->getVector()); + $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdge()); + $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdgeTo()); + $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdgeFrom()); } public function testDirectedLoopEdgeReturnsEdgeTwiceUndirectedAndOnceEachInAndOut() { $edge = $this->graph->createEdgeDirected($this->vertex, $this->vertex); - $this->assertEquals(array($edge, $edge), $this->vertex->getEdges()->getVector()); - $this->assertEquals(array($edge), $this->vertex->getEdgesIn()->getVector()); - $this->assertEquals(array($edge), $this->vertex->getEdgesOut()->getVector()); + $this->assertEquals(array($edge, $edge), $this->vertex->getEdges()); + $this->assertEquals(array($edge), $this->vertex->getEdgesIn()); + $this->assertEquals(array($edge), $this->vertex->getEdgesOut()); - $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdge()->getVector()); - $this->assertEquals(array($this->vertex), $this->vertex->getVerticesEdgeTo()->getVector()); - $this->assertEquals(array($this->vertex), $this->vertex->getVerticesEdgeFrom()->getVector()); + $this->assertEquals(array($this->vertex, $this->vertex), $this->vertex->getVerticesEdge()); + $this->assertEquals(array($this->vertex), $this->vertex->getVerticesEdgeTo()); + $this->assertEquals(array($this->vertex), $this->vertex->getVerticesEdgeFrom()); } public function testCreateEdgeOtherGraphFails() diff --git a/tests/WalkTest.php b/tests/WalkTest.php index 9084f487..29c9cc7a 100644 --- a/tests/WalkTest.php +++ b/tests/WalkTest.php @@ -4,8 +4,6 @@ use Graphp\Graph\Edge; use Graphp\Graph\Graph; -use Graphp\Graph\Set\Edges; -use Graphp\Graph\Set\Vertices; use Graphp\Graph\Walk; class WalkTest extends TestCase @@ -13,7 +11,7 @@ class WalkTest extends TestCase public function testWalkCanNotBeEmpty() { $this->setExpectedException('UnderflowException'); - Walk::factoryCycleFromVertices(new Vertices(array())); + Walk::factoryCycleFromVertices(array()); } public function testWalkPath() @@ -26,16 +24,16 @@ public function testWalkPath() $e1 = $graph->createEdgeDirected($v1, $v2); $e2 = $graph->createEdgeDirected($v2, $v3); - $walk = Walk::factoryFromEdges(new Edges(array($e1, $e2)), $v1); + $walk = Walk::factoryFromEdges(array($e1, $e2), $v1); $this->assertSame($graph, $walk->getGraph()); $this->assertEquals(3, count($walk->getVertices())); $this->assertEquals(2, count($walk->getEdges())); - $this->assertSame($v1, $walk->getVertices()->getVertexFirst()); - $this->assertSame($v3, $walk->getVertices()->getVertexLast()); - $this->assertSame(array($v1, $e1, $v2, $e2, $v3), $walk->getAlternatingSequence()); - return $walk; + $vertices = $walk->getVertices(); + $this->assertSame($v1, reset($vertices)); + $this->assertSame($v3, end($vertices)); + $this->assertSame(array($v1, $e1, $v2, $e2, $v3), $walk->getAlternatingSequence()); } public function testWalkWithinGraph() @@ -49,22 +47,85 @@ public function testWalkWithinGraph() $graph->createEdgeDirected($v2, $v3); // construct partial walk "1 -- 2" - $walk = Walk::factoryFromEdges(new Edges(array($e1)), $v1); + $walk = Walk::factoryFromEdges(array($e1), $v1); $this->assertSame($graph, $walk->getGraph()); $this->assertEquals(2, count($walk->getVertices())); $this->assertEquals(1, count($walk->getEdges())); - $this->assertSame($v1, $walk->getVertices()->getVertexFirst()); - $this->assertSame($v2, $walk->getVertices()->getVertexLast()); + + $vertices = $walk->getVertices(); + $this->assertSame($v1, reset($vertices)); + $this->assertSame($v2, end($vertices)); $this->assertSame(array($v1, $e1, $v2), $walk->getAlternatingSequence()); // construct same partial walk "1 -- 2" - $walkVertices = Walk::factoryFromVertices(new Vertices(array($v1, $v2))); + $walkVertices = Walk::factoryFromVertices(array($v1, $v2)); $this->assertEquals(2, count($walkVertices->getVertices())); $this->assertEquals(1, count($walkVertices->getEdges())); + } + + public function testFactoryFromEdgesWithTrivialGraphHasOneVertexAndNoEdges() + { + // 1 + $graph = new Graph(); + $v1 = $graph->createVertex(); + + $walk = Walk::factoryFromEdges(array(), $v1); + + $this->assertEquals(array($v1), $walk->getVertices()); + $this->assertEquals(array(), $walk->getEdges()); + } + + public function testFactoryFromEdgesWithArrayKeysWillBeIgnoredForGetEdges() + { + // 1 -- 2 + $graph = new Graph(); + $v1 = $graph->createVertex(); + $v2 = $graph->createVertex(); + $e1 = $graph->createEdgeDirected($v1, $v2); - return $walk; + $walk = Walk::factoryFromEdges(array('first' => $e1), $v1); + + $this->assertEquals(array($v1, $v2), $walk->getVertices()); + $this->assertEquals(array($e1), $walk->getEdges()); + } + + public function testFactoryFromVerticesWithTrivialGraphHasOneVertexAndNoEdges() + { + // 1 + $graph = new Graph(); + $v1 = $graph->createVertex(); + + $walk = Walk::factoryFromVertices(array($v1)); + + $this->assertEquals(array($v1), $walk->getVertices()); + $this->assertEquals(array(), $walk->getEdges()); + } + + public function testFactoryFromVerticesWithArrayKeysWillBeIgnoredForGetVertices() + { + // 1 -- 2 + $graph = new Graph(); + $v1 = $graph->createVertex(); + $v2 = $graph->createVertex(); + $e1 = $graph->createEdgeDirected($v1, $v2); + + $walk = Walk::factoryFromVertices(array('first' => $v1, 'second' => $v2)); + + $this->assertEquals(array($v1, $v2), $walk->getVertices()); + $this->assertEquals(array($e1), $walk->getEdges()); + } + + public function testFactoryFromVerticesWithUnconnectedComponentsThrows() + { + // 1, 2 + $graph = new Graph(); + $v1 = $graph->createVertex(); + $v2 = $graph->createVertex(); + + $this->setExpectedException('UnderflowException'); + Walk::factoryFromVertices(array($v1, $v2)); } public function testWalkLoop() @@ -74,14 +135,14 @@ public function testWalkLoop() $v1 = $graph->createVertex(); $e1 = $graph->createEdgeUndirected($v1, $v1); - $walk = Walk::factoryFromEdges(new Edges(array($e1)), $v1); + $walk = Walk::factoryFromEdges(array($e1), $v1); $this->assertEquals(2, count($walk->getVertices())); $this->assertEquals(1, count($walk->getEdges())); - $this->assertSame($v1, $walk->getVertices()->getVertexFirst()); - $this->assertSame($v1, $walk->getVertices()->getVertexLast()); - return $walk; + $vertices = $walk->getVertices(); + $this->assertSame($v1, reset($vertices)); + $this->assertSame($v1, end($vertices)); } public function testWalkLoopCycle() @@ -91,12 +152,14 @@ public function testWalkLoopCycle() $v1 = $graph->createVertex(); $e1 = $graph->createEdgeUndirected($v1, $v1); - $walk = Walk::factoryCycleFromEdges(new Edges(array($e1)), $v1); + $walk = Walk::factoryCycleFromEdges(array($e1), $v1); $this->assertEquals(2, count($walk->getVertices())); $this->assertEquals(1, count($walk->getEdges())); - $this->assertSame($v1, $walk->getVertices()->getVertexFirst()); - $this->assertSame($v1, $walk->getVertices()->getVertexLast()); + + $vertices = $walk->getVertices(); + $this->assertSame($v1, reset($vertices)); + $this->assertSame($v1, end($vertices)); } public function testWalkCycleFromVerticesIncomplete() @@ -110,7 +173,7 @@ public function testWalkCycleFromVerticesIncomplete() // should actually be [v1, v2, v1] $this->setExpectedException('InvalidArgumentException'); - Walk::factoryCycleFromVertices(new Vertices(array($v1, $v2))); + Walk::factoryCycleFromVertices(array($v1, $v2)); } public function testWalkCycleInvalid() @@ -122,7 +185,7 @@ public function testWalkCycleInvalid() $e1 = $graph->createEdgeUndirected($v1, $v2); $this->setExpectedException('InvalidArgumentException'); - Walk::factoryCycleFromEdges(new Edges(array($e1)), $v1); + Walk::factoryCycleFromEdges(array($e1), $v1); } public function testFactoryCycleFromEdgesWithLoopCycle() @@ -134,12 +197,14 @@ public function testFactoryCycleFromEdgesWithLoopCycle() $v1 = $graph->createVertex(); $e1 = $graph->createEdgeDirected($v1, $v1); - $cycle = Walk::factoryCycleFromEdges(new Edges(array($e1)), $v1); + $cycle = Walk::factoryCycleFromEdges(array($e1), $v1); $this->assertCount(2, $cycle->getVertices()); $this->assertCount(1, $cycle->getEdges()); - $this->assertSame($v1, $cycle->getVertices()->getVertexFirst()); - $this->assertSame($v1, $cycle->getVertices()->getVertexLast()); + + $vertices = $cycle->getVertices(); + $this->assertSame($v1, reset($vertices)); + $this->assertSame($v1, end($vertices)); } public function testFactoryCycleFromVerticesWithLoopCycle() @@ -151,12 +216,14 @@ public function testFactoryCycleFromVerticesWithLoopCycle() $v1 = $graph->createVertex(); $graph->createEdgeDirected($v1, $v1); - $cycle = Walk::factoryCycleFromVertices(new Vertices(array($v1, $v1))); + $cycle = Walk::factoryCycleFromVertices(array($v1, $v1)); $this->assertCount(2, $cycle->getVertices()); $this->assertCount(1, $cycle->getEdges()); - $this->assertSame($v1, $cycle->getVertices()->getVertexFirst()); - $this->assertSame($v1, $cycle->getVertices()->getVertexLast()); + + $vertices = $cycle->getVertices(); + $this->assertSame($v1, reset($vertices)); + $this->assertSame($v1, end($vertices)); } public function testFactoryCycleFromVerticesThrowsWhenCycleIsIncomplete() @@ -166,7 +233,7 @@ public function testFactoryCycleFromVerticesThrowsWhenCycleIsIncomplete() // should actually be [v1, v1] $this->setExpectedException('InvalidArgumentException'); - Walk::factoryCycleFromVertices(new Vertices(array($v1))); + Walk::factoryCycleFromVertices(array($v1)); } public function testFactoryFromVertices() @@ -181,26 +248,30 @@ public function testFactoryFromVertices() $e2 = $graph->createEdgeUndirected($v1, $v2)->setAttribute('weight', 20); // any edge in walk - $walk = Walk::factoryFromVertices(new Vertices(array($v1, $v2))); + $walk = Walk::factoryFromVertices(array($v1, $v2)); // edge with weight 10 - $walk = Walk::factoryFromVertices(new Vertices(array($v1, $v2)), function (Edge $edge) { + $walk = Walk::factoryFromVertices(array($v1, $v2), function (Edge $edge) { return $edge->getAttribute('weight'); }); - $this->assertSame($e1, $walk->getEdges()->getEdgeFirst()); + $edges = $walk->getEdges(); + $this->assertSame($e1, reset($edges)); // edge with weight 10 - $walk = Walk::factoryFromVertices(new Vertices(array($v1, $v2)), 'weight'); - $this->assertSame($e1, $walk->getEdges()->getEdgeFirst()); + $walk = Walk::factoryFromVertices(array($v1, $v2), 'weight'); + $edges = $walk->getEdges(); + $this->assertSame($e1, reset($edges)); // edge with weight 20 - $walk = Walk::factoryFromVertices(new Vertices(array($v1, $v2)), function (Edge $edge) { + $walk = Walk::factoryFromVertices(array($v1, $v2), function (Edge $edge) { return $edge->getAttribute('weight'); }, true); - $this->assertSame($e2, $walk->getEdges()->getEdgeFirst()); + $edges = $walk->getEdges(); + $this->assertSame($e2, reset($edges)); // edge with weight 20 - $walk = Walk::factoryFromVertices(new Vertices(array($v1, $v2)), 'weight', true); - $this->assertSame($e2, $walk->getEdges()->getEdgeFirst()); + $walk = Walk::factoryFromVertices(array($v1, $v2), 'weight', true); + $edges = $walk->getEdges(); + $this->assertSame($e2, reset($edges)); } }