Beispiel #1
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());
     }
 }
Beispiel #2
0
 /**
  * @return string
  */
 public function __toString()
 {
     $parts = [];
     /* @var Directed $edge */
     foreach ($this->walk->getEdges() as $edge) {
         $from = $this->getEntityClassName($edge->getVertexStart()->getId());
         $to = $this->getEntityClassName($edge->getVertexEnd()->getId());
         $parts[] = sprintf('  %s %s %s', str_pad($from, 20, ' ', STR_PAD_LEFT), str_pad($edge->getLayoutAttribute('label'), 15, '-', STR_PAD_BOTH) . '>', $to);
     }
     return implode("\n", $parts);
 }
Beispiel #3
0
 /**
  * get walk (path) from start vertex to given end vertex
  *
  * @param  Vertex    $endVertex
  * @return Walk
  * @throws OutOfBoundsException if there's no path to the given end vertex
  * @uses self::getEdgesTo()
  * @uses Walk::factoryFromEdges()
  */
 public function getWalkTo(Vertex $endVertex)
 {
     return Walk::factoryFromEdges($this->getEdgesTo($endVertex), $this->vertex);
 }
Beispiel #4
0
 /**
  * Calculate the Moore-Bellman-Ford-Algorithm and get all edges on shortest path for this vertex
  *
  * @return Edges
  * @throws NegativeCycleException if there is a negative cycle
  */
 public function getEdges()
 {
     // start node distance, add placeholder weight
     $totalCostOfCheapestPathTo = array($this->vertex->getId() => INF);
     // predecessor
     $predecessorVertexOfCheapestPathTo = array($this->vertex->getId() => $this->vertex);
     // the usal algorithm says we repeat (n-1) times.
     // but because we also want to check for loop edges on the start vertex,
     // we have to add an additional step:
     $numSteps = count($this->vertex->getGraph()->getVertices());
     $edges = $this->vertex->getGraph()->getEdges();
     $changed = true;
     for ($i = 0; $i < $numSteps && $changed; ++$i) {
         $changed = $this->bigStep($edges, $totalCostOfCheapestPathTo, $predecessorVertexOfCheapestPathTo);
     }
     // no cheaper edge to start vertex found => remove placeholder weight
     if ($totalCostOfCheapestPathTo[$this->vertex->getId()] === INF) {
         unset($predecessorVertexOfCheapestPathTo[$this->vertex->getId()]);
     }
     // algorithm is done, build graph
     $returnEdges = $this->getEdgesCheapestPredecesor($predecessorVertexOfCheapestPathTo);
     // Check for negative cycles (only if last step didn't already finish anyway)
     // something is still changing...
     if ($changed && ($changed = $this->bigStep($edges, $totalCostOfCheapestPathTo, $predecessorVertexOfCheapestPathTo))) {
         $cycle = Walk::factoryCycleFromPredecessorMap($predecessorVertexOfCheapestPathTo, $changed, Edges::ORDER_WEIGHT);
         throw new NegativeCycleException('Negative cycle found', 0, NULL, $cycle);
     }
     return $returnEdges;
 }
Beispiel #5
0
 /**
  * get (first) best circle connecting all vertices
  *
  * @return Walk
  * @uses AlgorithmTsp::getEdges()
  * @uses AlgorithmTsp::getVertexStart()
  * @uses Walk::factoryCycleFromEdges()
  */
 public function getCycle()
 {
     return Walk::factoryCycleFromEdges($this->getEdges(), $this->getVertexStart());
 }
Beispiel #6
0
 public function testFactoryFromVertices()
 {
     // 1 -- 2
     // \----/
     $graph = new Graph();
     $v1 = $graph->createVertex(1);
     $v2 = $graph->createVertex(2);
     $e1 = $v1->createEdge($v2)->setWeight(10);
     $e2 = $v1->createEdge($v2)->setWeight(20);
     // any edge in walk
     $walk = Walk::factoryFromVertices(array($v1, $v2));
     // edge with weight 10
     $walk = Walk::factoryFromVertices(array($v1, $v2), Edges::ORDER_WEIGHT);
     $this->assertSame($e1, $walk->getEdges()->getEdgeFirst());
     // edge with weight 20
     $walk = Walk::factoryFromVertices(array($v1, $v2), Edges::ORDER_WEIGHT, true);
     $this->assertSame($e2, $walk->getEdges()->getEdgeFirst());
 }
Beispiel #7
0
 /**
  * checks whether walk is eulerian (i.e. a walk over ALL EDGES of the graph)
  *
  * @return boolean
  * @see self::isHamiltonian() if you want to check for all VERTICES instead of EDGES
  * @uses self::isArrayContentsEqual()
  * @link http://en.wikipedia.org/wiki/Eulerian_path
  */
 public function isEulerian()
 {
     return $this->isArrayContentsEqual($this->walk->getEdges()->getVector(), $this->walk->getGraph()->getEdges()->getVector());
 }
Beispiel #8
0
 /**
  * Store properties to be cleared
  *
  * Because we're only exporting data, we don't need to actually update
  * the data at all for the clear to be respected. We just need to modify
  * what we write to the exported files.
  *
  * @param \Fhaculty\Graph\Walk $walk
  * @param array $fields
  * @param array $joinFields
  * @return mixed
  */
 public function processClear(Walk $walk, array $fields, array $joinFields)
 {
     $this->clear[$walk->getVertexSource()->getId()] = ['fields' => $fields, 'joinFields' => $joinFields];
 }
Beispiel #9
0
 public function testSimplePathWithinGraph()
 {
     // 1 -- 2 -- 2
     $graph = new Graph();
     $v1 = $graph->createVertex(1);
     $v2 = $graph->createVertex(2);
     $e1 = $v1->createEdge($v2);
     $e2 = $v2->createEdge($v2);
     // only use "2 -- 2" part
     $walk = Walk::factoryFromEdges(array($e2), $v2);
     $this->assertEquals(2, count($walk->getVertices()));
     $this->assertEquals(1, count($walk->getEdges()));
     $alg = new WalkProperty($walk);
     $this->assertTrue($alg->isCycle());
     $this->assertTrue($alg->hasCycle());
     $this->assertTrue($alg->isPath());
     $this->assertTrue($alg->isSimple());
     $this->assertFalse($alg->isEulerian());
     $this->assertFalse($alg->isHamiltonian());
 }
Beispiel #10
0
 /**
  * @expectedException InvalidArgumentException
  */
 public function testInvalidPredecessors()
 {
     $graph = new Graph();
     $v1 = $graph->createVertex(1);
     Walk::factoryCycleFromPredecessorMap(array(), $v1);
 }