예제 #1
0
 public function getEdges()
 {
     $alg = new Directed($this->graph);
     if ($alg->hasDirected()) {
         throw new UnexpectedValueException('Input graph contains directed edges');
     }
     $alg = new Groups($this->graph);
     if (!$alg->isBipartit()) {
         throw new UnexpectedValueException('Input graph does not have bipartit groups assigned to each vertex. Consider Using "AlgorithmBipartit::createGraph()" first');
     }
     // create temporary flow graph with supersource and supersink
     $graphFlow = $this->graph->createGraphCloneEdgeless();
     $superSource = $graphFlow->createVertex();
     $superSink = $graphFlow->createVertex();
     $groups = $alg->getGroups();
     $groupA = $groups[0];
     $groupB = $groups[1];
     // connect supersource s* to set A and supersink t* to set B
     foreach ($graphFlow->getVertices() as $vertex) {
         // we want to skip over supersource & supersink as they do not have a partition assigned
         if ($vertex === $superSource || $vertex === $superSink) {
             continue;
         }
         $group = $vertex->getGroup();
         // source
         if ($group === $groupA) {
             $superSource->createEdgeTo($vertex)->setCapacity(1)->setFlow(0);
             // temporarily create edges from A->B for flow graph
             $originalVertex = $this->graph->getVertex($vertex->getId());
             foreach ($originalVertex->getVerticesEdgeTo() as $vertexTarget) {
                 $vertex->createEdgeTo($graphFlow->getVertex($vertexTarget->getId()))->setCapacity(1)->setFlow(0);
             }
             // sink
         } elseif ($group === $groupB) {
             $vertex->createEdgeTo($superSink)->setCapacity(1)->setFlow(0);
         } else {
             // @codeCoverageIgnoreStart
             throw new LogicException('Should not happen. Unknown set: ' + $belongingSet);
             // @codeCoverageIgnoreEnd
         }
     }
     // visualize($resultGraph);
     // calculate (s*, t*)-flow
     $algMaxFlow = new MaxFlowEdmondsKarp($superSource, $superSink);
     $resultGraph = $algMaxFlow->createGraph();
     // destroy temporary supersource and supersink again
     $resultGraph->getVertex($superSink->getId())->destroy();
     $resultGraph->getVertex($superSource->getId())->destroy();
     $returnEdges = array();
     foreach ($resultGraph->getEdges() as $edge) {
         // only keep matched edges
         if ($edge->getFlow() > 0) {
             $originalEdge = $this->graph->getEdgeClone($edge);
             $returnEdges[] = $originalEdge;
         }
     }
     return new Edges($returnEdges);
 }
예제 #2
0
 public function createGraph()
 {
     $this->checkBalance();
     // create resulting graph with supersource and supersink
     $resultGraph = $this->graph->createGraphClone();
     $superSource = $resultGraph->createVertex();
     $superSink = $resultGraph->createVertex();
     $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;
 }
예제 #3
0
 /**
  * @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());
 }