public function getOutput(Graph $graph) { $output = ''; // build an array to map vertex IDs (which may contain complex strings) to temporary numeric IDs for output $tid = 1; $tids = array(); foreach ($graph->getVertices()->getMap() as $vid => $vertex) { $output .= $tid . ' ' . $this->getVertexLabel($vertex) . self::EOL; $tids[$vid] = $tid++; } // end of vertex list, start of edge list $output .= '#' . self::EOL; foreach ($graph->getEdges() as $edge) { /* @var $edge Edge */ $ids = $edge->getVertices()->getIds(); $a = $tids[$ids[0]]; $b = $tids[$ids[1]]; $label = $this->getEdgeLabel($edge); if ($label !== '') { $label = ' ' . $label; } $output .= $a . ' ' . $b . $label . self::EOL; // this is not a directed edge => also add back-edge with same label if (!$edge instanceof Directed) { $output .= $b . ' ' . $a . $label . self::EOL; } } return $output; }
public function extract(FhacultyGraph $graph) { $this->data = array('edges' => array(), 'vertices' => array(), 'cycles' => $this->extractEntities($graph->getAttribute('cycles', array())), 'groups' => $graph->getAttribute('graphviz.groups', array()), 'log' => $graph->getAttribute('logEntries', array()), 'label' => $graph->getAttribute('graphviz.graph.label')); $edges = $graph->getEdges(); foreach ($edges as $edge) { /** @var Directed $edge */ $this->addEdge($edge); $this->addVertex($edge->getVertexStart()); $this->addVertex($edge->getVertexEnd()); } ksort($this->data['edges']); ksort($this->data['vertices']); return $this->data; }
/** * @return Edges */ public function getCycledEdges() { $allCycleEdges = array(); foreach ($this->getCycles() as $cycle) { $cycledEdges = $cycle->getEdges(); foreach ($cycledEdges as $cycledEdge) { if (!in_array($cycledEdge, $allCycleEdges)) { $allCycleEdges[] = $cycledEdge->toArray(); } } } return $this->graph->getEdges()->getEdgesMatch(function (Directed $edge) use($allCycleEdges) { $search = array($edge->getVertexStart()->getId(), $edge->getVertexEnd()->getId()); return in_array($search, $allCycleEdges); }); }
public function getOutput(Graph $graph) { $root = new SimpleXMLElement(self::SKEL); $graphElem = $root->addChild('graph'); $graphElem['edgeDefault'] = 'undirected'; foreach ($graph->getVertices()->getMap() as $id => $vertex) { /* @var $vertex Vertex */ $vertexElem = $graphElem->addChild('node'); $vertexElem['id'] = $id; } foreach ($graph->getEdges() as $edge) { /* @var $edge Edge */ $edgeElem = $graphElem->addChild('edge'); $edgeElem['source'] = $edge->getVertices()->getVertexFirst()->getId(); $edgeElem['target'] = $edge->getVertices()->getVertexLast()->getId(); if ($edge instanceof Directed) { $edgeElem['directed'] = 'true'; } } return $root->asXML(); }
/** * * @return Edges */ public function getEdges() { // Sortiere Kanten im Graphen $sortedEdges = new SplPriorityQueue(); // For all edges $this->addEdgesSorted($this->graph->getEdges(), $sortedEdges); $returnEdges = array(); // next color to assign $colorNext = 0; // array(color1 => array(vid1, vid2, ...), color2=>...) $colorVertices = array(); // array(vid1 => color1, vid2 => color1, ...) $colorOfVertices = array(); // Füge billigste Kanten zu neuen Graphen hinzu und verschmelze teilgragen wenn es nötig ist (keine Kreise) // solange ich mehr als einen Graphen habe mit weniger als n-1 kanten (bei n knoten im original) foreach ($sortedEdges as $edge) { /* @var $edge EdgeDirected */ // Gucke Kante an: $vertices = $edge->getVertices()->getIds(); $aId = $vertices[0]; $bId = $vertices[1]; $aColor = isset($colorOfVertices[$aId]) ? $colorOfVertices[$aId] : NULL; $bColor = isset($colorOfVertices[$bId]) ? $colorOfVertices[$bId] : NULL; // 1. weder start noch end gehört zu einem graphen // => neuer Graph mit kanten if ($aColor === NULL && $bColor === NULL) { $colorOfVertices[$aId] = $colorNext; $colorOfVertices[$bId] = $colorNext; $colorVertices[$colorNext] = array($aId, $bId); ++$colorNext; // connect both vertices $returnEdges[] = $edge; } else { if ($aColor === NULL && $bColor !== NULL) { // paint a in b's color $colorOfVertices[$aId] = $bColor; $colorVertices[$bColor][] = $aId; $returnEdges[] = $edge; // Only a has color } elseif ($aColor !== NULL && $bColor === NULL) { // paint b in a's color $colorOfVertices[$bId] = $aColor; $colorVertices[$aColor][] = $bId; $returnEdges[] = $edge; } else { if ($aColor !== $bColor) { $betterColor = $aColor; $worseColor = $bColor; // more vertices with color a => paint all in b in a's color if (count($colorVertices[$bColor]) > count($colorVertices[$aColor])) { $betterColor = $bColor; $worseColor = $aColor; } // search all vertices with color b foreach ($colorVertices[$worseColor] as $vid) { $colorOfVertices[$vid] = $betterColor; // repaint in a's color $colorVertices[$betterColor][] = $vid; } // delete old color unset($colorVertices[$worseColor]); $returnEdges[] = $edge; } } } // 2. start und end gehören zum gleichen graphen => zirkel // => nichts machen } // definition of spanning tree: number of edges = number of vertices - 1 // above algorithm does not check isolated edges or may otherwise return multiple connected components => force check if (count($returnEdges) !== count($this->graph->getVertices()) - 1) { throw new UnexpectedValueException('Graph is not connected'); } return new Edges($returnEdges); }
public function testRemoveEdge() { // 1 -- 2 $graph = new Graph(); $v1 = $graph->createVertex(1); $v2 = $graph->createVertex(2); $edge = $v1->createEdge($v2); $this->assertEquals(array($edge), $graph->getEdges()->getVector()); $edge->destroy(); //$graph->removeEdge($edge); $this->assertEquals(array(), $graph->getEdges()->getVector()); return $graph; }
public function testOrderByGroup() { $graph = new Graph(); $v1 = $graph->createVertex(1); $v2 = $graph->createVertex(2); $v1->createEdge($v2)->setWeight(1); $v1->createEdge($v2)->setWeight(100); $v1->createEdge($v2)->setWeight(5); $v1->createEdge($v2)->setWeight(100); $v1->createEdge($v2)->setWeight(100); $v1->createEdge($v2)->setWeight(2); $biggest = $v1->createEdge($v2)->setWeight(200); $edges = $graph->getEdges(); $edgesOrdered = $edges->getEdgesOrder(Edges::ORDER_WEIGHT); $this->assertInstanceOf('Fhaculty\\Graph\\Set\\Edges', $edgesOrdered); $this->assertEquals(1, $edgesOrdered->getEdgeFirst()->getWeight()); $this->assertEquals(200, $edgesOrdered->getEdgeLast()->getWeight()); $this->assertSame($biggest, $edgesOrdered->getEdgeLast()); $this->assertSame($biggest, $edges->getEdgeOrder(Edges::ORDER_WEIGHT, true)); $sumweights = function (Edge $edge) { return $edge->getWeight(); }; $this->assertSame(508, $edges->getSumCallback($sumweights)); $this->assertSame(508, $edgesOrdered->getSumCallback($sumweights)); }
/** * create graphviz script representing this graph * * @return string * @uses Directed::hasDirected() * @uses Graph::getVertices() * @uses Graph::getEdges() */ public function createScript() { $alg = new Directed($this->graph); $directed = $alg->hasDirected(); $script = ($directed ? 'di' : '') . 'graph G {' . self::EOL; // add global attributes $layout = $this->graph->getLayout(); if ($layout) { $script .= $this->formatIndent . 'graph ' . $this->escapeAttributes($layout) . self::EOL; } if ($this->layoutVertex) { $script .= $this->formatIndent . 'node ' . $this->escapeAttributes($this->layoutVertex) . self::EOL; } if ($this->layoutEdge) { $script .= $this->formatIndent . 'edge ' . $this->escapeAttributes($this->layoutEdge) . self::EOL; } $alg = new Groups($this->graph); // only append group number to vertex label if there are at least 2 different groups $showGroups = $alg->getNumberOfGroups() > 1; if ($showGroups) { $gid = 0; $indent = str_repeat($this->formatIndent, 2); // put each group of vertices in a separate subgraph cluster foreach ($alg->getGroups() as $group) { $script .= $this->formatIndent . 'subgraph cluster_' . $gid++ . ' {' . self::EOL . $indent . 'label = ' . $this->escape($group) . self::EOL; foreach ($alg->getVerticesGroup($group)->getMap() as $vid => $vertex) { $layout = $this->getLayoutVertex($vertex); $script .= $indent . $this->escapeId($vid); if ($layout) { $script .= ' ' . $this->escapeAttributes($layout); } $script .= self::EOL; } $script .= ' }' . self::EOL; } } else { $alg = new Degree($this->graph); // explicitly add all isolated vertices (vertices with no edges) and vertices with special layout set // other vertices wil be added automatically due to below edge definitions foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) { $layout = $this->getLayoutVertex($vertex); if ($layout || $alg->isVertexIsolated($vertex)) { $script .= $this->formatIndent . $this->escapeId($vid); if ($layout) { $script .= ' ' . $this->escapeAttributes($layout); } $script .= self::EOL; } } } $edgeop = $directed ? ' -> ' : ' -- '; // add all edges as directed edges foreach ($this->graph->getEdges() as $currentEdge) { $both = $currentEdge->getVertices()->getVector(); $currentStartVertex = $both[0]; $currentTargetVertex = $both[1]; $script .= $this->formatIndent . $this->escapeId($currentStartVertex->getId()) . $edgeop . $this->escapeId($currentTargetVertex->getId()); $layout = $this->getLayoutEdge($currentEdge); // this edge also points to the opposite direction => this is actually an undirected edge if ($directed && $currentEdge->isConnection($currentTargetVertex, $currentStartVertex)) { $layout['dir'] = 'none'; } if ($layout) { $script .= ' ' . $this->escapeAttributes($layout); } $script .= self::EOL; } $script .= '}' . self::EOL; return $script; }