Example #1
0
 public function createGraph()
 {
     $this->checkBalance();
     // create resulting graph with supersource and supersink
     $resultGraph = $this->graph->createGraphClone();
     $superSource = $resultGraph->createVertex()->setLayoutAttribute('label', 's*');
     $superSink = $resultGraph->createVertex()->setLayoutAttribute('label', 't*');
     $sumBalance = 0;
     // connect supersource s* and supersink t* with all "normal" sources and sinks
     foreach ($resultGraph->getVertices() as $vertex) {
         $balance = $vertex->getBalance();
         if ($balance > 0) {
             // positive balance => source capacity
             $superSource->createEdgeTo($vertex)->setCapacity($balance);
             $sumBalance += $balance;
         } elseif ($balance < 0) {
             // negative balance => sink capacity (positive)
             $vertex->createEdgeTo($superSink)->setCapacity(-$balance);
         }
     }
     // calculate (s*, t*)-flow
     $algMaxFlow = new MaxFlowEdmondsKarp($superSource, $superSink);
     $flowMax = $algMaxFlow->getFlowMax();
     if ($flowMax !== $sumBalance) {
         throw new UnexpectedValueException('Network does not support required flow of ' . $sumBalance . ' (maximum possible flow limited to ' . $flowMax . ')');
     }
     $resultGraph = $algMaxFlow->createGraph();
     while (true) {
         // create residual graph
         $algRG = new ResidualGraph($resultGraph);
         $residualGraph = $algRG->createGraph();
         // get negative cycle
         $alg = new DetectNegativeCycle($residualGraph);
         try {
             $clonedEdges = $alg->getCycleNegative()->getEdges();
         } catch (UnderflowException $ignore) {
             // no negative cycle found => end algorithm
             break;
         }
         // calculate maximal possible flow = minimum capacity remaining for all edges
         $newFlow = $clonedEdges->getEdgeOrder(Edges::ORDER_CAPACITY_REMAINING)->getCapacityRemaining();
         // set flow on original graph
         $this->addFlow($resultGraph, $clonedEdges, $newFlow);
     }
     // destroy temporary supersource and supersink again
     $resultGraph->getVertex($superSink->getId())->destroy();
     $resultGraph->getVertex($superSource->getId())->destroy();
     return $resultGraph;
 }
Example #2
0
 public function testNegativeComponents()
 {
     // 1 -- 2     3 --[-1]--> 4
     //            ^           |
     //            \---[-2]----/
     $graph = new Graph();
     $v1 = $graph->createVertex(1);
     $v2 = $graph->createVertex(2);
     $v3 = $graph->createVertex(3);
     $v4 = $graph->createVertex(4);
     $e1 = $v1->createEdge($v2);
     $e2 = $v3->createEdgeTo($v4)->setWeight(-1);
     $e3 = $v4->createEdgeTo($v3)->setWeight(-2);
     $alg = new DetectNegativeCycle($graph);
     $this->assertTrue($alg->hasCycleNegative());
     $cycle = $alg->getCycleNegative();
     $this->assertCount(2, $cycle->getEdges());
     $this->assertCount(3, $cycle->getVertices());
     $this->assertTrue($cycle->getVertices()->hasVertexId(3));
     $this->assertTrue($cycle->getVertices()->hasVertexId(4));
 }