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; }
/** * @expectedException UnexpectedValueException */ public function testEdgesUndirected() { // 0 -[0/7]- 1 $graph = new Graph(); $v0 = $graph->createVertex(0); $v1 = $graph->createVertex(1); $v1->createEdge($v0)->setCapacity(7); // 0 -[7/7]- 1 $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1); $this->assertEquals(7, $alg->getFlowMax()); }