Пример #1
0
 /**
  * create subgraph with all vertices connected to given vertex (i.e. the connected component of ths given vertex)
  *
  * @param  Vertex                   $vertex
  * @return Graph
  * @throws InvalidArgumentException if given vertex is not from same graph
  * @uses AlgorithmSearchBreadthFirst::getVertices()
  * @uses Graph::createGraphCloneVertices()
  */
 public function createGraphComponentVertex(Vertex $vertex)
 {
     if ($vertex->getGraph() !== $this->graph) {
         throw new InvalidArgumentException('This graph does not contain the given vertex');
     }
     return $this->graph->createGraphCloneVertices($this->createSearch($vertex)->getVertices());
 }
Пример #2
0
 protected function getVerticesParent(Vertex $vertex)
 {
     $vertices = $vertex->getVerticesEdgeFrom();
     if ($vertices->hasDuplicates()) {
         throw new UnexpectedValueException();
     }
     return $vertices;
 }
Пример #3
0
 public function getIndexVertex(Vertex $vertex)
 {
     $id = $vertex->getId();
     if (!isset($this->vertices[$id]) || $this->vertices[$id] !== $vertex) {
         throw new OutOfBoundsException();
     }
     return $id;
 }
Пример #4
0
 /**
  * checks whether this vertex has a loop (edge to itself)
  *
  * @return boolean
  * @uses Edge::isLoop()
  */
 public function hasLoopVertex(Vertex $vertex)
 {
     foreach ($vertex->getEdges() as $edge) {
         if ($edge->isLoop()) {
             return true;
         }
     }
     return false;
 }
Пример #5
0
 /**
  * @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());
     }
 }
Пример #6
0
 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');
 }
Пример #7
0
 /**
  * create a new undirected edge between given vertices
  *
  * @param Vertex $a
  * @param Vertex $b
  * @see Vertex::createEdge() instead
  */
 public function __construct(Vertex $a, Vertex $b)
 {
     if ($a->getGraph() !== $b->getGraph()) {
         throw new InvalidArgumentException('Vertices have to be within the same graph');
     }
     $this->a = $a;
     $this->b = $b;
     $a->getGraph()->addEdge($this);
     $a->addEdge($this);
     $b->addEdge($this);
 }
Пример #8
0
 /**
  * create a new directed Edge from Vertex $from to Vertex $to
  *
  * @param Vertex $from start/source Vertex
  * @param Vertex $to   end/target Vertex
  * @see Vertex::createEdgeTo() to create directed edges
  * @see Vertex::createEdge() to create undirected edges
  */
 public function __construct(Vertex $from, Vertex $to)
 {
     if ($from->getGraph() !== $to->getGraph()) {
         throw new InvalidArgumentException('Vertices have to be within the same graph');
     }
     $this->from = $from;
     $this->to = $to;
     $from->getGraph()->addEdge($this);
     $from->addEdge($this);
     $to->addEdge($this);
 }
Пример #9
0
 protected function getVerticesAdjacent(Vertex $vertex)
 {
     if ($this->direction === self::DIRECTION_FORWARD) {
         return $vertex->getVerticesEdgeTo();
     } elseif ($this->direction === self::DIRECTION_REVERSE) {
         return $vertex->getVerticesEdgeFrom();
     } elseif ($this->direction === self::DIRECTION_BOTH) {
         return $vertex->getVerticesEdge();
     } else {
         throw new DomainException('Should not happen. Invalid direction setting');
     }
 }
Пример #10
0
 /**
  *
  * 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);
         }
     }
 }
Пример #11
0
 /**
  * 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);
 }
Пример #12
0
 /**
  * Calculates the flow for this Vertex: sum(outflow) - sum(inflow)
  *
  * Usually, vertices should have a resulting flow of 0: The sum of flows
  * entering a vertex must equal the sum of flows leaving a vertex. If the
  * resulting flow is < 0, this vertex is considered a sink (i.e. there's
  * more flow into this vertex). If the resulting flow is > 0, this vertex
  * is considered a "source" (i.e. there's more flow leaving this vertex).
  *
  * @param Vertex $vertex
  * @return float
  * @throws UnexpectedValueException if they are undirected edges
  * @see Vertex::getBalance()
  * @uses Vertex::getEdges()
  * @uses Edge::getFlow()
  */
 public function getFlowVertex(Vertex $vertex)
 {
     $sumOfFlow = 0;
     foreach ($vertex->getEdges() as $edge) {
         if (!$edge instanceof EdgeDirected) {
             throw new UnexpectedValueException("TODO: undirected edges not suported yet");
         }
         // edge is an outgoing edge of this vertex
         if ($edge->hasVertexStart($vertex)) {
             // flowing out (flow is "pointing away")
             $sumOfFlow += $edge->getFlow();
             // this is an ingoing edge
         } else {
             // flowing in
             $sumOfFlow -= $edge->getFlow();
         }
     }
     return $sumOfFlow;
 }
Пример #13
0
 /**
  * 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;
 }
Пример #14
0
 /**
  * @param Vertex $vertex
  * @return \Fhaculty\Graph\Edge\Directed
  */
 private function createEdgeToAdtRootVertexBy(Vertex $vertex)
 {
     foreach ($this->adtRootVertex->getEdges() as $edge) {
         /** @var \Fhaculty\Graph\Edge\Directed $edge */
         if ($edge->isConnection($this->adtRootVertex, $vertex)) {
             return $edge;
         }
     }
     return $this->adtRootVertex->createEdgeTo($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;
 }
Пример #16
0
 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;
     }
 }
Пример #17
0
 /**
  *
  * @return Edges
  */
 public function getEdges()
 {
     $returnEdges = array();
     $n = count($this->vertex->getGraph()->getVertices());
     $vertex = $this->vertex;
     $visitedVertices = array($vertex->getId() => true);
     for ($i = 0; $i < $n - 1; ++$i, $vertex = $nextVertex) {
         // get all edges from the aktuel vertex
         $edges = $vertex->getEdgesOut();
         $sortedEdges = new SplPriorityQueue();
         // sort the edges
         foreach ($edges as $edge) {
             $sortedEdges->insert($edge, -$edge->getWeight());
         }
         // Untill first is found: get cheepest edge
         foreach ($sortedEdges as $edge) {
             // Get EndVertex of this edge
             $nextVertex = $edge->getVertexToFrom($vertex);
             // is unvisited
             if (!isset($visitedVertices[$nextVertex->getId()])) {
                 break;
             }
         }
         // check if there is a way i can use
         if (isset($visitedVertices[$nextVertex->getId()])) {
             throw new UnexpectedValueException('Graph is not complete - can\'t find an edge to unconnected vertex');
         }
         $visitedVertices[$nextVertex->getId()] = TRUE;
         // clone edge in new Graph
         $returnEdges[] = $edge;
     }
     // check if there is a way from end edge to start edge
     // get first connecting edge
     // connect the last vertex with the start vertex
     $returnEdges[] = $vertex->getEdgesTo($this->vertex)->getEdgeFirst();
     return new Edges($returnEdges);
 }
Пример #18
0
 /**
  * get neighbor vertices for given start vertex
  *
  * @param Vertex $vertex
  * @throws UnexpectedValueException for directed edges
  * @return Vertices (might include possible duplicates)
  * @uses Vertex::getEdges()
  * @uses Edge::getVertexToFrom()
  * @see Vertex::getVerticesEdge()
  */
 private function getVerticesNeighbor(Vertex $vertex)
 {
     $vertices = array();
     foreach ($vertex->getEdges() as $edge) {
         /* @var Edge $edge */
         if (!$edge instanceof UndirectedEdge) {
             throw new UnexpectedValueException('Directed edge encountered');
         }
         $vertices[] = $edge->getVertexToFrom($vertex);
     }
     return new Vertices($vertices);
 }
Пример #19
0
 /**
  * get outdegree of this vertex (number of edges FROM this vertex TO other vertices)
  *
  * @param Vertex $vertex
  * @return int
  * @uses Edge::hasVertexStart()
  * @see self::getDegreeVertex()
  */
 public function getDegreeOutVertex(Vertex $vertex)
 {
     $n = 0;
     foreach ($vertex->getEdges() as $edge) {
         if ($edge->hasVertexStart($vertex)) {
             ++$n;
         }
     }
     return $n;
 }
Пример #20
0
 /**
  * @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());
 }
Пример #21
0
 protected function createAlg(Vertex $vertex)
 {
     return new Kruskal($vertex->getGraph());
 }
Пример #22
0
 /**
  * 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 addBalance(Vertex $vertex, $balance)
 {
     $vertex->setBalance($vertex->getBalance() + $balance);
 }
Пример #24
0
 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];
 }
Пример #25
0
 /**
  * get set of Edges FROM the given vertex TO this vertex
  *
  * @param  Vertex $vertex
  * @return Edges
  * @uses Vertex::getEdgesTo()
  */
 public function getEdgesFrom(Vertex $vertex)
 {
     return $vertex->getEdgesTo($this);
 }
Пример #26
0
 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;
 }
Пример #27
0
 protected function getGraph()
 {
     return $this->startVertex->getGraph();
 }
Пример #28
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;
 }
Пример #29
0
 /**
  *
  * @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;
 }
Пример #30
0
 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;
 }