public function getEdgesTo(Vertex $endVertex) { if ($endVertex->getGraph() === $this->vertex->getGraph()) { $map = $this->getEdgesMap(); if (isset($map[$endVertex->getId()])) { return new Edges($map[$endVertex->getId()]); } } throw new OutOfBoundsException('Given target vertex can not be reached from start vertex'); }
/** * * calculates the recursive algorithm * * fills $this->visitedVertices * * @param Vertex $vertex */ private function recursiveDepthFirstSearch(Vertex $vertex, array &$visitedVertices) { // If I didn't visited this vertex before if (!isset($visitedVertices[$vertex->getId()])) { // Add Vertex to already visited vertices $visitedVertices[$vertex->getId()] = $vertex; // Get next vertices $nextVertices = $vertex->getVerticesEdgeTo(); foreach ($nextVertices as $nextVertix) { // recursive call for next vertices $this->recursiveDepthFirstSearch($nextVertix, $visitedVertices); } } }
public function getIndexVertex(Vertex $vertex) { $id = $vertex->getId(); if (!isset($this->vertices[$id]) || $this->vertices[$id] !== $vertex) { throw new OutOfBoundsException(); } return $id; }
/** * @param Vertex $vertex * @return Walk */ protected function getWalkForVertex(Vertex $vertex) { if ($vertex->getId() == $this->graph->getRoot()) { return Walk::factoryFromEdges([], $vertex); } else { $shortestPath = new BreadthFirst($vertex); return $shortestPath->getWalkTo($this->vertices->getVertexLast()); } }
/** * Returns max flow value * * @return double */ public function getFlowMax() { $resultGraph = $this->createGraph(); $start = $resultGraph->getVertex($this->startVertex->getId()); $maxFlow = 0; foreach ($start->getEdgesOut() as $edge) { $maxFlow = $maxFlow + $edge->getFlow(); } return $maxFlow; }
protected function visit(Vertex $vertex, array &$visited, array &$tsl) { $vid = $vertex->getId(); if (isset($visited[$vid])) { if ($visited[$vid] === false) { // temporary mark => not a DAG throw new UnexpectedValueException('Not a DAG'); } // otherwise already marked/visisted => no need to check again } else { // temporary mark $visited[$vid] = false; foreach (array_reverse($vertex->getVerticesEdgeTo()->getVector()) as $v) { $this->visit($v, $visited, $tsl); } // mark as visited and include in result $visited[$vid] = true; $tsl[$vid] = $vertex; } }
/** * get label for given $vertex * * @param Vertex $vertex * @return string */ protected function getVertexLabel(Vertex $vertex) { // label defaults to the vertex ID $label = $vertex->getId(); // add balance to label if set $balance = $vertex->getBalance(); if ($balance !== NULL) { if ($balance > 0) { $balance = '+' . $balance; } $label .= ' (' . $balance . ')'; } // add group to label if set // TODO: what does 'if set' mean? groups should not be shown when vertex never had any group assigned (but it defaults to 0) // $group = $vertex->getGroup(); // if ($group !== 0) { // $label .= ' [' . $group .']'; // } return $label; }
/** * * @param Vertex $vertex current point-of-view * @param number $totalWeight total weight (so far) * @param boolean[] $visitedVertices * @param Edge[] $visitedEdges * @return Edge[] */ private function step(Vertex $vertex, $totalWeight, array $visitedVertices, array $visitedEdges) { // stop recursion if best result is exceeded (branch and bound) if ($this->branchAndBound && $this->bestWeight !== NULL && $totalWeight >= $this->bestWeight) { return NULL; } // kreis geschlossen am Ende if ($vertex === $this->startVertex && count($visitedEdges) === $this->numEdges) { // new best result $this->bestWeight = $totalWeight; return $visitedEdges; } // only visit each vertex once if (isset($visitedVertices[$vertex->getId()])) { return NULL; } $visitedVertices[$vertex->getId()] = true; $bestResult = NULL; // weiter verzweigen in alle vertices foreach ($vertex->getEdgesOut() as $edge) { // get target vertex of this edge $target = $edge->getVertexToFrom($vertex); $weight = $edge->getWeight(); if ($weight < 0) { throw new UnexpectedValueException('Edge with negative weight "' . $weight . '" not supported'); } $result = $this->step($target, $totalWeight + $weight, $visitedVertices, array_merge($visitedEdges, array($edge))); // new result found if ($result !== NULL) { // branch and bound enabled (default): returned result MUST be the new best result if ($this->branchAndBound || $bestResult === NULL || $this->sumEdges($result) < $this->sumEdges($bestResult)) { $bestResult = $result; } } } return $bestResult; }
/** * @param Vertex $vertex * @return array */ private function extractVertex(Vertex $vertex) { $locations = $this->extractEntities($vertex->getAttribute('locations', array())); return array('name' => $vertex->getId(), 'usedByCount' => $vertex->getEdgesIn()->count(), 'adt' => $vertex->getAttribute('adt', array()), 'location' => array_shift($locations), 'group' => $vertex->getGroup()); }
/** * helper method to get recursively get subtree for given $vertex * * @param Vertex $vertex * @param Vertex[] $vertices * @throws UnexpectedValueException if multiple links were found to the given edge (check isTree()!) * @uses self::getVerticesChildren() * @uses self::getVerticesSubtreeRecursive() to recurse into subtrees */ private function getVerticesSubtreeRecursive(Vertex $vertex, array &$vertices) { $vid = $vertex->getId(); if (isset($vertices[$vid])) { throw new UnexpectedValueException('Multiple links found'); } $vertices[$vid] = $vertex; foreach ($this->getVerticesChildren($vertex) as $vertexChild) { $this->getVerticesSubtreeRecursive($vertexChild, $vertices); } }
private function getEdgeCloneInternal(Edge $edge, Vertex $startVertex, Vertex $targetVertex) { // Get original vertices from resultgraph $residualGraphEdgeStartVertex = $this->getVertex($startVertex->getId()); $residualGraphEdgeTargetVertex = $this->getVertex($targetVertex->getId()); // Now get the edge $residualEdgeArray = $residualGraphEdgeStartVertex->getEdgesTo($residualGraphEdgeTargetVertex); $residualEdgeArray = Edges::factory($residualEdgeArray)->getVector(); // Check for parallel edges if (!$residualEdgeArray) { throw new UnderflowException('No original edges for given cloned edge found'); } elseif (count($residualEdgeArray) !== 1) { throw new OverflowException('More than one cloned edge? Parallel edges (multigraph) not supported'); } return $residualEdgeArray[0]; }
/** * adds a new Vertex to the Graph (MUST NOT be called manually!) * * @param Vertex $vertex instance of the new Vertex * @return void * @private * @see self::createVertex() instead! */ public function addVertex(Vertex $vertex) { assert($vertex instanceof Vertex); if (isset($this->verticesStorage[$vertex->getId()])) { throw new OverflowException('ID must be unique'); } $this->verticesStorage[$vertex->getId()] = $vertex; }
/** * get subtree for given Vertex and ignore path to "parent" ignoreVertex * * @param Vertex $vertex * @param Vertex[] $vertices * @param Vertex|null $ignore * @throws UnexpectedValueException for cycles or directed edges (check isTree()!) * @uses self::getVerticesNeighbor() * @uses self::getVerticesSubtreeRecursive() to recurse into sub-subtrees */ private function getVerticesSubtreeRecursive(Vertex $vertex, array &$vertices, Vertex $ignore = null) { if (isset($vertices[$vertex->getId()])) { // vertex already visited => must be a cycle throw new UnexpectedValueException('Vertex already visited'); } $vertices[$vertex->getId()] = $vertex; foreach ($this->getVerticesNeighbor($vertex) as $vertexNeighboor) { if ($vertexNeighboor === $ignore) { // ignore source vertex only once $ignore = null; continue; } $this->getVerticesSubtreeRecursive($vertexNeighboor, $vertices, $vertex); } }
protected function getLayoutVertex(Vertex $vertex) { $layout = $vertex->getLayout(); $balance = $vertex->getBalance(); if ($balance !== NULL) { if ($balance > 0) { $balance = '+' . $balance; } if (!isset($layout['label'])) { $layout['label'] = $vertex->getId(); } $layout['label'] .= ' (' . $balance . ')'; } return $layout; }
/** * create new cycle instance from given predecessor map * * @param Vertex[] $predecessors map of vid => predecessor vertex instance * @param Vertex $vertex start vertex to search predecessors from * @param int|null $by * @param boolean $desc * @return Walk * @throws UnderflowException * @see Edges::getEdgeOrder() for parameters $by and $desc * @uses self::factoryFromVertices() */ public static function factoryCycleFromPredecessorMap(array $predecessors, Vertex $vertex, $by = null, $desc = false) { // find a vertex in the cycle $vid = $vertex->getId(); $startVertices = array(); do { if (!isset($predecessors[$vid])) { throw new InvalidArgumentException('Predecessor map is incomplete and does not form a cycle'); } $startVertices[$vid] = $vertex; $vertex = $predecessors[$vid]; $vid = $vertex->getId(); } while (!isset($startVertices[$vid])); // find negative cycle $vid = $vertex->getId(); // build array of vertices in cycle $vertices = array(); do { // add new vertex to cycle $vertices[$vid] = $vertex; // get predecessor of vertex $vertex = $predecessors[$vid]; $vid = $vertex->getId(); // continue until we find a vertex that's already in the circle (i.e. circle is closed) } while (!isset($vertices[$vid])); // reverse cycle, because cycle is actually built in opposite direction due to checking predecessors $vertices = array_reverse($vertices, true); // additional edge from last vertex to first vertex $vertices[] = reset($vertices); return self::factoryCycleFromVertices($vertices, $by, $desc); }
protected function getLayoutVertex(Vertex $vertex) { $bag = new AttributeBagNamespaced($vertex, 'graphviz.'); $layout = $bag->getAttributes(); $balance = $vertex->getBalance(); if ($balance !== NULL) { if ($balance > 0) { $balance = '+' . $balance; } if (!isset($layout['label'])) { $layout['label'] = $vertex->getId(); } $layout['label'] .= ' (' . $balance . ')'; } return $layout; }