/**
  * Searches all vertices for the first negative cycle
  *
  * @return Walk
  * @throws UnderflowException if there's no negative cycle
  * @uses AlgorithmSpMooreBellmanFord::getVertices()
  */
 public function getCycleNegative()
 {
     // remember vertices already visited, as they can not lead to a new cycle
     $verticesVisited = array();
     // check for all vertices
     foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {
         // skip vertices already visited
         if (!isset($verticesVisited[$vid])) {
             // start MBF algorithm on current vertex
             $alg = new SpMooreBellmanFord($vertex);
             try {
                 // try to get all connected vertices (or throw new cycle)
                 foreach ($alg->getVertices()->getIds() as $vid) {
                     // getting connected vertices succeeded, so skip over all of them
                     $verticesVisited[$vid] = true;
                     // no cycle found, check next vertex...
                 }
                 // yey, negative cycle encountered => return
             } catch (NegativeCycleException $e) {
                 return $e->getCycle();
             }
         }
         // no more vertices to check => abort
     }
     throw new UnderflowException('No negative cycle found');
 }
 /**
  * @uses Graph::createGraphClone()
  * @uses ResidualGraph::createGraph()
  * @uses SpMooreBellmanFord::getEdgesTo(Vertex $targetVertex)
  * @see Base::createGraph()
  */
 public function createGraph()
 {
     $this->checkBalance();
     $resultGraph = $this->graph->createGraphClone();
     // initial balance to 0
     $vertices = $resultGraph->getVertices();
     foreach ($vertices as $vertex) {
         $vertex->setBalance(0);
     }
     // initial flow of edges
     $edges = $resultGraph->getEdges();
     foreach ($edges as $edge) {
         if (!$edge instanceof EdgeDirected) {
             throw new UnexpectedValueException('Undirected edges are not supported for SuccessiveShortestPath');
         }
         // 0 if weight of edge is positive
         $flow = 0;
         // maximal flow if weight of edge is negative
         if ($edge->getWeight() < 0) {
             $flow = $edge->getCapacity();
             $startVertex = $edge->getVertexStart();
             $endVertex = $edge->getVertexEnd();
             // add balance to start- and end-vertex
             $this->addBalance($startVertex, $flow);
             $this->addBalance($endVertex, -$flow);
         }
         $edge->setFlow($flow);
     }
     // return or Exception inside this while
     while (true) {
         // create residual graph
         $algRG = new ResidualGraph($resultGraph);
         $residualGraph = $algRG->createGraph();
         // search for a source
         try {
             $sourceVertex = $this->getVertexSource($residualGraph);
         } catch (UnderflowException $ignore) {
             // no source is found => minimum-cost flow is found
             break;
         }
         // search for reachable target sink from this source
         try {
             $targetVertex = $this->getVertexSink($sourceVertex);
         } catch (UnderflowException $e) {
             // no target found => network does not have enough capacity
             throw new UnexpectedValueException('The graph has not enough capacity for the minimum-cost flow', 0, $e);
         }
         // calculate shortest path between source- and target-vertex
         $algSP = new SpMooreBellmanFord($sourceVertex);
         $edgesOnFlow = $algSP->getEdgesTo($targetVertex);
         // calculate the maximal possible flow
         // new flow is the maximal possible flow for this path
         $newflow = $this->graph->getVertex($sourceVertex->getId())->getBalance() - $sourceVertex->getBalance();
         $targetFlow = -($this->graph->getVertex($targetVertex->getId())->getBalance() - $targetVertex->getBalance());
         // get minimum of source and target
         if ($targetFlow < $newflow) {
             $newflow = $targetFlow;
         }
         // get minimum of capacity remaining on path
         $minCapacity = $edgesOnFlow->getEdgeOrder(Edges::ORDER_CAPACITY_REMAINING)->getCapacityRemaining();
         if ($minCapacity < $newflow) {
             $newflow = $minCapacity;
         }
         // add the new flow to the path
         $this->addFlow($resultGraph, $edgesOnFlow, $newflow);
         // add balance to source and remove for the target sink
         $oriSourceVertex = $resultGraph->getVertex($sourceVertex->getId());
         $oriTargetVertex = $resultGraph->getVertex($targetVertex->getId());
         $this->addBalance($oriSourceVertex, $newflow);
         $this->addBalance($oriTargetVertex, -$newflow);
     }
     return $resultGraph;
 }
 /**
  * @param MooreBellmanFord $alg
  * @depends testGraphParallelNegative
  * @expectedException UnderflowException
  */
 public function testNoNegativeCycle(MooreBellmanFord $alg)
 {
     $alg->getCycleNegative();
 }