Exemplo n.º 1
0
 /**
  * @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;
 }